unit facecat;

{$mode objfpc}{$H+}

interface
uses 
  math,SysUtils;  

var
  globalUID:integer;

const
  WM_PAINT = 15;
  WM_SIZE = 5;
  WM_LBUTTONDOWN = 513;
  WM_MOUSEMOVE = 512;
  WM_LBUTTONUP = 514;
  WM_LBUTTONDBLCLK = 515;
  WM_RBUTTONDOWN = 516;
  WM_RBUTTONUP = 517;
  WM_RBUTTONDBLCLK = 518;
  WM_MOUSEWHEEL = 522;
  WM_IME_COMPOSITION = 271;
  WM_IME_CHAR = 646;
  WM_IME_SETCONTEXT = 641;
  WM_CHAR = 258;
  WM_KEYDOWN = 256;
  WM_KEYUP = 257;
  WM_SYSKEYDOWN = 260;
  WM_SYSKEYUP = 261;

function ShowWindow2():integer;stdcall;
external 'facecatcpp.dll' name 'showWindow2';

function GetMessage():integer;stdcall;
external 'facecatcpp.dll' name 'getMessage';

function DoMessage():integer;stdcall;
external 'facecatcpp.dll' name 'doMessage';

function ShowWindowMax():integer;stdcall;
external 'facecatcpp.dll' name 'showWindowMax';

function BeginWmPaint(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'beginWmPaint';

function EndWmPaint(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'endWmPaint';

function CreateGdiPlus(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'createGdiPlus';

function BeginPaintGdiPlus2(gID:integer; wLeft:integer; wTop:integer; wRight:integer; wBottom:integer; pLeft:integer; pTop:integer; pRight:integer; pBottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'beginPaintGdiPlus2';

function EndPaintGdiPlus(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'endPaintGdiPlus';

function SetOffsetGdiPlus(gID:integer;offsetX:integer;offsetY:integer):integer;stdcall;
external 'facecatcpp.dll' name 'setOffsetGdiPlus';

function DrawTextWithPosGdiPlus2(gID:integer;strText:PChar;dwPenColor:longint;font:PChar;x:integer;y:integer):integer;stdcall;
external 'facecatcpp.dll' name 'drawTextWithPosGdiPlus2';

function GetTextSizeWidth():integer;stdcall;
external 'facecatcpp.dll' name 'getTextSizeWidth';

function GetTextSizeHeight():integer;stdcall;
external 'facecatcpp.dll' name 'getTextSizeHeight';

function TextSizeGdiPlus4(gID:integer;strText:PChar;font:PChar;width:integer):integer;stdcall;
external 'facecatcpp.dll' name 'textSizeGdiPlus4';

function GetWindowWidth(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getWindowWidth';

function GetWindowHeight(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getWindowHeight';

function DrawLineGdiPlus(gID:integer;dwPenColor:longint;width:single;style:integer;x1:integer;y1:integer;x2:integer;y2:integer):integer;stdcall;
external 'facecatcpp.dll' name 'drawLineGdiPlus';

function DrawRectGdiPlus(gID:integer;dwPenColor:longint;width:single;style:integer;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'drawRectGdiPlus';

function FillRectGdiPlus(gID:integer;dwPenColor:longint;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'fillRectGdiPlus';

function DrawRoundRectGdiPlus(gID:integer;dwPenColor:longint;width:single;style:integer;left:integer;top:integer;right:integer;bottom:integer;cornerRadius:integer):integer;stdcall;
external 'facecatcpp.dll' name 'drawRoundRectGdiPlus';

function FillRoundRectGdiPlus(gID:integer;dwPenColor:longint;left:integer;top:integer;right:integer;bottom:integer;cornerRadius:integer):integer;stdcall;
external 'facecatcpp.dll' name 'fillRoundRectGdiPlus';

function DrawEllipseGdiPlus(gID:integer;dwPenColor:longint;width:single;style:integer;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'drawEllipseGdiPlus';

function FillEllipseGdiPlus(gID:integer;dwPenColor:longint;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'fillEllipseGdiPlus';

function DrawPolylineGdiPlus(gID:integer;dwPenColor:longint;width:single;style:integer;strApt:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'drawPolylineGdiPlus';

function DrawPolygonGdiPlus(gID:integer;dwPenColor:longint;width:single;style:integer;strApt:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'drawPolygonGdiPlus';

function FillPolygonGdiPlus(gID:integer;dwPenColor:longint;strApt:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'fillPolygonGdiPlus';

function SetClipGdiPlus(gID:integer;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'setClipGdiPlus';

function GetMouseX(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getMouseX';

function GetMouseY(gID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getMouseY';

function SetMessageState(id:integer;state:integer):integer;stdcall;
external 'facecatcpp.dll' name 'setMessageState';

function CreateView(gID:integer;typeStr:PChar;nameStr:PChar):integer;stdcall;external 'facecatcpp.dll' name 'createView';

function SetAttribute2(gID:integer;nameStr:PChar;atrName:PChar;atrValue:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'setAttribute2';

function PaintView(gID:integer;nameStr:PChar;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'paintView';

function FocusView(gID:integer;nameStr:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'focusView';

function UnFocusView(gID:integer;nameStr:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'unFocusView';

function MouseDownView(gID:integer;nameStr:PChar;x:integer;y:integer;buttons:integer;clicks:integer):integer;stdcall;
external 'facecatcpp.dll' name 'mouseDownView';

function MouseUpView(gID:integer;nameStr:PChar;x:integer;y:integer;buttons:integer;clicks:integer):integer;stdcall;
external 'facecatcpp.dll' name 'mouseUpView';

function MouseMoveView(gID:integer;nameStr:PChar;x:integer;y:integer;buttons:integer;clicks:integer):integer;stdcall;
external 'facecatcpp.dll' name 'mouseMoveView';

function MouseWheelView(gID:integer;nameStr:PChar;x:integer;y:integer;buttons:integer;clicks:integer;delta:integer):integer;stdcall;
external 'facecatcpp.dll' name 'mouseWheelView';

function InvalidateViewW32(hWnd:integer;left:integer;top:integer;right:integer;bottom:integer):integer;stdcall;
external 'facecatcpp.dll' name 'invalidateView';

function GetHWnd():integer;stdcall;
external 'facecatcpp.dll' name 'getHWnd';  

function StrToColor(str:PChar):longint;stdcall;
external 'facecatcpp.dll' name 'strToColor';  

function ReadXmlDoc(str:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'readXmlDoc';  

function DeleteXmlDoc():integer;stdcall;
external 'facecatcpp.dll' name 'deleteXmlDoc';  

function GetXmlRootNode():integer;stdcall;
external 'facecatcpp.dll' name 'getXmlRootNode';  

function GetXmlNodeName(nodeID:integer):PChar;stdcall;
external 'facecatcpp.dll' name 'getXmlNodeName';  

function GetXmlChildNodesCount(nodeID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getXmlChildNodesCount';  

function GetXmlChildNodeID(nodeID:integer;idx:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getXmlChildNodeID';  

function GetXmlAttributesCount(nodeID:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getXmlAttributesCount';  

function GetXmlAttrName(nodeID:integer;idx:integer):PChar;stdcall;
external 'facecatcpp.dll' name 'getXmlAttrName';  

function GetXmlAttrValue(nodeID:integer;idx:integer):PChar;stdcall;
external 'facecatcpp.dll' name 'getXmlAttrValue';  

function IndexOfStr(str:PChar;findStr:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'indexOfStr';  

function SplitStr(str:PChar;splitWord:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'splitStr';  

function GetSplitStrToInt(idx:integer):integer;stdcall;
external 'facecatcpp.dll' name 'getSplitStrToInt';  

function SetCursor(gID:integer;cursor:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'setCursor';  

function RemoveViewCpp(gID:integer;cursor:PChar):integer;stdcall;
external 'facecatcpp.dll' name 'removeView';  

function PumpMessage():integer;stdcall;
external 'facecatcpp.dll' name 'pumpMessage'; 

type  
  WndProcCallBack = procedure(hWnd:integer; message:integer; wParam:integer; lParam: integer); cdecl;  

procedure RegisterWndProc(func:WndProcCallBack);stdcall;
external 'facecatcpp.dll' name 'registerWndProc';  

type
  DoubleArray = array of double;

{坐标结构}
type 
  FCPoint = class  
  public 
    x: double; //横坐标
    y: double; //纵坐标
    isNotEmpty:boolean;
	  constructor Create(inx, iny: double);  
end;

{大小结构}
type 
  FCSize = class  
  public 
    cx: double; //长
    cy: double; //宽
    isNotEmpty:boolean;
	  constructor Create(icx, icy: double);  
end;

{矩形结构}
type 
  FCRect = class  
  public 
    left: double; //左侧
    top: double; //上侧
    right: double; //右侧
    bottom: double; //底部
    isNotEmpty:boolean;
	  constructor Create(ileft, itop, iright, ibottom: double);  
end;

{边距信息}
type 
  FCPadding = class  
  public 
    left: double; //左侧
    top: double; //上侧
    right: double; //右侧
    bottom: double; //底部
    isNotEmpty:boolean;
	  constructor Create(ileft, itop, iright, ibottom: double);  
end;

function ToColorGdiPlus(strColor:string):longint;

{绘图对象}
type 
FCPaint = class
  public
    cancelClick: boolean; //是否退出点击
    clipRect:FCRect;
    defaultUIStyle: string; //默认样式
    dragBeginPoint: FCPoint; //拖动开始时的触摸位置
    dragBeginRect: FCRect; //拖动开始时的区域
    gID:integer;
    hWnd:integer;
    isDoubleClick:boolean;
    isNotEmpty:boolean;
    offsetX: double; //横向偏移
    offsetY: double; //纵向偏移
    resizeColumnState: integer; //改变列宽度的状态
    resizeColumnBeginWidth: double; //改变列宽度的起始值
    resizeColumnIndex: integer; //改变列宽度的索引
    scaleFactorX: double; //横向缩放比例
    scaleFactorY: double; //纵向缩放比例
    size: FCSize; //大小
    systemFont: string; //系统字体
    touchDownPoint: FCPoint;
    constructor Create(); 
    procedure BeginPaint(rect:FCRect; pRect:FCRect);
    procedure DrawLine(color:string; width:integer; style:integer; x1:double; y1:double; x2:double; y2:double);
    procedure DrawPolyline(color:string; width:integer; style:integer; apt:array of FCPoint);
    procedure DrawPolygon(color:string; width:integer; style:integer; apt:array of FCPoint);
    procedure DrawRect(color:string; width:integer; style:integer; left:double; top:double; right:double; bottom:double);
    procedure DrawRoundRect(color:string; width:integer; style:integer; left:double; top:double; right:double; bottom:double; cornerRadius:double);
    procedure DrawEllipse(color:string; width:integer; style:integer; left:double; top:double; right:double; bottom:double);
    procedure DrawText(text:string; color:string; font:string; x:double; y:double);
    procedure EndPaint();
    procedure FillRect(color:string; left:double; top:double; right:double; bottom:double);
    procedure FillRoundRect(color:string; left:double; top:double; right:double; bottom:double; cornerRadius:double);
    procedure FillPolygon(color:string; apt:array of FCPoint);
    procedure FillEllipse(color:string; left:double; top:double; right:double; bottom:double);
    procedure SetOffset(x:double; y:double);
    procedure SetClip(left:double; top:double; right:double; bottom:double);
    function TextSize(text:string;font:string):FCSize;
    procedure DrawTextAutoEllipsis(text:string; color:string; font:string; left:double; top:double; right:double; bottom:double);
end;

{基础视图}
type 
  FCView = class  
  public 
    align: string; //横向布局
    allowDrag: boolean; //是否允许拖动
    allowResize:boolean; //是否可以拖动改变大小
    allowDragScroll: boolean; //是否允许拖动滚动
    allowPreviewsEvent: boolean; //是否允许预处理事件
    autoHide:boolean;
    backColor: string; //背景色
    backImage: string; //背景图片
    borderColor : string; //边线色
    borderWidth : integer; //边线宽度
    clipRect: FCRect; //裁剪区域
    cornerRadius: double; //圆角
    cursor: string; //光标
    displayOffset: boolean; //是否显示偏移量
    dock: string; //悬浮状态
    downScrollHButton: boolean;  //是否按下横向滚动条
    downScrollVButton: boolean; //是否按下纵向滚动条
    enabled: boolean;  //是否可用
    exView:boolean;
    font: string; //字体
    hoveredColor: string; //鼠标悬停时的颜色
    hoverScrollHButton: boolean; //是否悬停横向滚动条
    hoverScrollVButton: boolean; //是否悬停纵向滚动条
    hScrollIsVisible:boolean; //横向滚动是否显示
    isNotEmpty:boolean;
    location: FCPoint; //坐标
    margin: FCPadding; //外边距
    maximumSize: FCSize; //大小
    padding:FCPadding; //内边距
    paint:array of FCPaint; //绘图对象
    parent:array of FCView; //父视图
    pushedColor: string; //鼠标按下时的颜色
    resizePoint:integer;//调整尺寸的点
    scrollV: double; //纵向滚动
    scrollH: double; //横向滚动
    scrollSize: double; //滚动条的大小
    showHScrollBar: boolean; //是否显示横向滚动条
    showVScrollBar: boolean; //是否显示横向滚动条
    scrollBarColor: string;  //滚动条的颜色
    scrollBarHoveredColor: string;  //滚动条悬停的颜色
    size: FCSize; //大小
    startScrollH: double; //开始滚动的值
    startScrollV: double; //结束滚动的值
    startPoint: FCPoint; //起始坐标
    startRect:FCRect; //移动开始时的视图矩形
    tabIndex:integer;//Tab索引
    tabStop:boolean; ////是否支持Tab
    tag: string; //数据
    text: string; //文字
    textColor: string; //前景色
    topMost: boolean; //是否置顶
    touchDownTime: integer; //鼠标按下的时间
    viewName: string; //名称
    verticalAlign : string; //纵向布局
    viewType: string; //类型
    visible : boolean; //可见性
    vScrollIsVisible : boolean; //纵向滚动是否显示
    views: array of FCView; //子视图
    uid:integer;
    constructor Create();  
    function GetParent():FCView;
    function GetPaint():FCPaint;
    procedure SetParent(p:FCView);
    procedure SetPaint(p:FCPaint);
end;

type
  viewArray = array of FCView;

{按钮}
type 
  FCButton = class(FCView)
  public
    constructor Create(); 
end;

{标签}
type 
  FCLabel = class(FCView)
  public
    constructor Create(); 
end;

{图层}
type 
  FCDiv = class(FCView)
  public
    constructor Create(); 
end;

{文本框}
type 
  FCTextBox = class(FCView)
  public
    constructor Create(); 
end;

{页}
type 
  FCTabPage = class(FCView)
  public
    headerButton:FCView;
    constructor Create(); 
end;

{多页夹}
type 
  FCTabView = class(FCView)
  public
    animationSpeed: integer; //动画速度
    layout: string; //布局方式
    tabPages: array of FCTabPage; //页夹集合
    underLineColor: string; //下划线的颜色
    underLineSize: double; //下划线的宽度
    underPoint: FCPoint; //下划点
    useAnimation: boolean; //是否使用动画
    constructor Create(); 
end;

{复选按钮}
type 
  FCCheckBox = class(FCView)
  public
    buttonSize: FCSize; //按钮的大小
    checked: boolean; //是否选中
    constructor Create(); 
end;

{单选按钮}
type 
  FCRadioButton = class(FCView)
  public
    buttonSize: FCSize; //按钮的大小
    checked: boolean; //是否选中
    groupName: string; //组别
    constructor Create(); 
end;

{多布局图层}
type 
  FCLayoutDiv = class(FCView)
  public
    autoWrap: boolean; //是否自动换行
    layoutStyle: string; //分割方式
    constructor Create(); 
end;

{分割图层}
type 
  FCSplitLayoutDiv = class(FCView)
  public
    firstView: FCView; //第一个视图
    layoutStyle: string; //分割方式
    oldSize: FCSize; //上次的尺寸
    secondView: FCView; //第二个视图
    splitter: FCView; //分割线
    splitMode: string; //分割模式 percentsize百分比 或absolutesize绝对值
    splitPercent: double; //分割百分比
    constructor Create(); 
end;

{表格列}
type 
  FCGridColumn = class
  public
    allowSort: boolean; //是否允许排序
    allowResize: boolean; //是否允许改变大小
    backColor: string; //背景色
    borderColor: string; //边线颜色
    bounds: FCRect; //区域
    cellAlign: string; //left:居左 center:居中 right:居右
    colName: string; //名称
    colType: string; //类型 string:字符串 double:浮点型 int:整型 bool:布尔型
    font: string; //字体
    frozen: boolean; //是否冻结
    colIndex: integer; //索引
    isNotEmpty:boolean;
    sort: string; //排序模式
    text: string; //文字
    textColor: string; //文字颜色
    visible: boolean; //是否可见
    width: double; //宽度
    widthStr: string; //宽度字符串
    constructor Create(); 
end;

{表格单元格}
type 
  FCGridCell = class
  public
    backColor: string; //背景色
    borderColor: string; //边线色
    column:FCGridColumn; //所在列
    colSpan: integer; //列距
    digit: integer; //保留小数的位数
    font: string; //字体
    isNotEmpty:boolean;
    rowSpan: integer; //行距
    textColor: string; //前景色
    value: string; //值
    constructor Create(); 
end;

{表格行}
type 
  FCGridRow = class
  public
    rowIndex: integer; //索引
    isNotEmpty:boolean;
    selected: boolean; //是否选中
    visible: boolean; //是否可见
    cells:array of FCGridCell;
    constructor Create(); 
end;

{表格}
type 
  FCGrid = class(FCView)
  public
    columns:array of FCGridColumn;
    headerHeight: double; //头部高度
    rowHeight: double; //行高
    rows:array of FCGridRow;
    selectedRowColor: string; //选中行的颜色
    constructor Create(); 
end;

{树的列}
type 
  FCTreeColumn = class
  public
    bounds: FCRect; //区域
    colIndex: integer; //索引
    isNotEmpty:boolean;
    visible: boolean; //是否可见
    width: double; //宽度
    constructor Create(); 
end;

{树的节点}
type 
  FCTreeNode = class
  public
    allowCollapsed: boolean; //是否允许折叠
    backColor: string; //背景色
    checked: boolean; //是否选中
    collapsed: boolean; //是否折叠
    font: string; //字体
    isNotEmpty:boolean;
    indent: double; //缩进
    rowIndex:integer;
    textColor: string; //前景色
    value: string; //值
    childNodes:array of FCTreeNode;
    parentNode:array of FCTreeNode;
    constructor Create(); 
    function GetParentNode():FCTreeNode;
    procedure SetParentNode(p:FCTreeNode);
end;

{树的行}
type 
  FCTreeRow = class
  public
    cells:array of FCTreeNode;
    isNotEmpty:boolean;
    rowIndex: integer; //索引
    selected: boolean; //是否选中
    visible: boolean; //是否可见
    constructor Create(); 
end;

{树}
type 
  FCTree = class(FCView)
  public
    checkBoxWidth: double; //复选框占用的宽度
    collapsedWidth: double; //折叠按钮占用的宽度
    columns:array of FCTreeColumn;
    headerHeight: double; //头部高度
    indent: double; //缩进
    rowHeight: double; //行高
    rows:array of FCTreeRow;
    selectedRowColor: string; //选中行的颜色
    showCheckBox: boolean; //是否显示复选框
    childNodes:array of FCTreeNode;
    constructor Create(); 
end;

{证券数据结构}
type 
  SecurityData = class
  public
    amount: double; //成交额
    close: double; //收盘价
    date: double; //日期，为1970年到现在的秒
    high: double; //最高价
    low: double; //最低价
    open: double; //开盘价
    volume: double; //成交额
end;

{基础图形}
type 
  BaseShape = class
  public
    color: string; //颜色
    color2: string; //颜色2
    datas:DoubleArray; //第一组数据
    datas2:DoubleArray;  //第二组数据
    divIndex: integer; //所在层
    isNotEmpty:boolean;
    leftOrRight: boolean; //依附于左轴或右轴
    lineWidth: integer; //线的宽度
    shapeName: string; //名称
    shapeType: string; //类型
    showHideDatas:DoubleArray;
    style: string; //样式
    text: string; //显示的文字
    title: string; //第一个标题
    title2: string; //第二个标题
    value: double; //显示文字的值
    constructor Create(); 
end;

{画线工具结构}
type 
  FCPlot = class
  public
    isNotEmpty:boolean;
    lineColor: string; //线的颜色
    lineWidth: integer; //线的宽度
    pointColor: string; //线的颜色
    plotType: string; //线的类型
    key1: double; //第一个键
    key2: double; //第二个键
    key3: double; //第三个键
    startKey1: double; //移动前第一个键
    startValue1: double; //移动前第一个值
    startKey2: double; //移动前第二个键
    startValue2: double; //移动前第二个值
    startKey3: double; //移动前第三个键
    startValue3: double; //移动前第三个值
    value1: double; //第一个值
    value2: double; //第二个值
    value3 : double; //第三个值
    uid:integer;
    constructor Create(); 
end;

{图表}
type 
  FCChart = class(FCView)
  public
    autoFillHScale: boolean; //是否填充满X轴
    allowDragChartDiv: boolean; //是否允许拖拽图层
    candleDistance: double; //蜡烛线的距离
    candleMax: double; //蜡烛线的最大值
    candleMin: double; //蜡烛线的最小值
    candleMaxRight: double; //蜡烛线的右轴最大值
    candleMinRight: double; //蜡烛线的右轴最小值
    crossTipColor: string; //十字线标识的颜色
    crossLineColor: string;//十字线的颜色
    candlePaddingTop: double; //图表层的上边距
    candlePaddingBottom: double; //图表层的下边距
    candleDigit: integer; //图表层保留小数的位数
    candleDivPercent: double; //图表层的占比
    crossStopIndex: integer; //鼠标停留位置
    cycle: string; //周期
    downColor: string; //下跌颜色
    data:array of SecurityData; //数据
    firstVisibleIndex: integer; //起始可见的索引
    gridColor: string; //网格颜色
    lastVisibleIndex: integer; //结束可见的索引
    leftVScaleWidth: double; //左轴宽度
    lastRecordIsVisible: boolean; //最后记录是否可见
    lastVisibleKey: double; //最后可见的主键
    hScalePixel: double; //蜡烛线的宽度
    hScaleHeight: double; //X轴的高度
    hScaleTextDistance: double; //X轴的文字间隔
    hScaleFormat: string; //X轴的格式化字符，例如YYYY-mm-dd HH:MM:SS
    indMax: double; //指标层的最大值
    indMin: double; //指标的最小值
    indMaxRight: double; //指标层的右轴最大值
    indMinRight: double; //指标层的右轴最小值
    indDigit: integer; //指标层保留小数的位数
    indDivPercent: double; //指标层的占比
    indPaddingTop: double; //指标层的上边距
    indPaddingBottom: double; //指标层的下边距
    indicatorColors:array of string;
    lastValidIndex: integer; //最后有效数据索引
    lineWidthChart: integer;
    mainIndicator: string; //主图指标
    magnitude: integer; //成交量的比例
    midColor: string; //中间色
    offsetX:double; //横向绘图偏移
    plots:array of FCPlot; //画线
    plotPointSizeChart: double; //画线的选中点大小
    rightVScaleWidth: double; //右轴宽度
    rightSpace: double; //右侧空间
    scaleColor: string; //刻度的颜色
    showIndicator: string; //显示指标
    showCrossLine: boolean; //是否显示十字线
    selectPlotPoint: integer; //选中画线的点
    shapes:array of BaseShape;
    startMovePlot: boolean; //选中画线
    selectShape: string; //选中的图形
    selectShapeEx: string; //选中的图形信息
    targetOldX : double; //缩小时旧的位置1
		targetOldX2 :double; //放大时旧的位置2
    sPlot: FCPlot; //选中的线条
    touchPosition: FCPoint; //鼠标坐标
    trendColor : string; //分时线颜色
    volMax: double; //成交量层的最大值
    volMin: double; //成交量层的最小值
    volMaxRight: double; //成交量层的右轴最大值
    volMinRight: double; //成交量层的右轴最小值
    volDigit: integer; //成交量层保留小数的位数
    volDivPercent: double; //成交量层的占比
    volPaddingTop: double; //成交量层的上边距
    volPaddingBottom: double; //成交量层的下边距
    vScaleDistance: double; //纵轴的间隔
    vScaleType: string; //纵轴的类型 log10代表指数坐标
    upColor: string; //上涨颜色
    kChart: double;
    bChart: double;
    oXChart: double;
    oYChart: double;
    rChart: double;
    gridStepChart: double; //网格计算临时变量
    gridDigitChart: integer; //网格计算临时变量
    candleStyle:string;
    barStyle:string;
    firstOpen:double;
    vScaleTextColor:string; //纵轴的文字颜色
    hScaleTextColor:string;//横轴的文字颜色
    firstIndexCacheChart: integer;
    firstTouchIndexCacheChart: integer;
    firstTouchPointCacheChart: FCPoint;
    lastIndexCacheChart: integer;
    secondTouchIndexCacheChart: integer;
    secondTouchPointCacheChart: FCPoint;
    firstPaddingTop: double;
    firstPaddingBottom: double;
    touchDownPointChart: FCPoint;
    addingPlotChart: string;
    x4Chart: double;
    y4Chart: double;
    nHighChart: double;
    nLowChart: double;
    xChart: double;
    yChart: double;
    wChart: double;
    hChart: double;
    upSubValue: double;
    downSubValue: double;
    allema12:DoubleArray;
    allema26: DoubleArray;
    alldifarr: DoubleArray;
    alldeaarr: DoubleArray;
    allmacdarr: DoubleArray;
    bollUp: DoubleArray;
    bollDown: DoubleArray;
    bollMid: DoubleArray;
    bias1: DoubleArray;
    bias2: DoubleArray;
    bias3: DoubleArray;
    kdjK: DoubleArray;
    kdjD: DoubleArray;
    kdjJ: DoubleArray;
    rsi1: DoubleArray;
    rsi2: DoubleArray;
    rsi3: DoubleArray;
    roc: DoubleArray;
    rocMa: DoubleArray;
    wr1: DoubleArray;
    wr2: DoubleArray;
    cci: DoubleArray;
    bbi: DoubleArray;
    trix: DoubleArray;
    trixMa: DoubleArray;
    dma1: DoubleArray;
    dma2: DoubleArray;
    ma5: DoubleArray;
    ma10: DoubleArray;
    ma20: DoubleArray;
    ma30: DoubleArray;
    ma120: DoubleArray;
    ma250: DoubleArray;
    closeArr: DoubleArray;
    constructor Create(); 
end;

{日的结构}
type 
  CDay = class
  public
    day: integer; //日
    isNotEmpty:boolean;
    month: integer; //月
    year: integer; //年
    constructor Create(); 
end;

{月的结构}
type 
  CMonth = class
  public
    isNotEmpty:boolean;
    month: integer; //月
    year: integer; //年
    days:array of CDay;
    constructor Create(); 
end;

{年的结构}
type 
  CYear = class
  public
    isNotEmpty:boolean;
    year: integer; //年
    months:array of CMonth;
    constructor Create(); 
end;

{日的按钮}
type 
  DayButton = class
  public
    backColor: string; //背景颜色
    borderColor: string; //文字颜色
    bounds: FCRect; //显示区域
    day: CDay; //日期
    font: string; //字体
    isNotEmpty:boolean;
    inThisMonth: boolean;//是否在本月
    selected: boolean; //是否被选中
    textColor: string; //文字颜色
    textColor2: string;  //第二个文字颜色
    visible: boolean; //是否可见
    constructor Create(); 
end;

{月的按钮}
type 
  MonthButton = class
  public
    backColor: string; //背景颜色
    borderColor: string; //文字颜色
    bounds: FCRect; //显示区域
    font: string; //字体
    isNotEmpty:boolean;
    month: integer; //月
    textColor: string; //文字颜色
    year: integer; //年
    visible: boolean; //是否可见
    constructor Create(); 
end;

{年的按钮}
type 
  YearButton = class
  public
    backColor: string; //背景颜色
    borderColor: string; //文字颜色
    bounds: FCRect; //显示区域
    font: string; //字体
    isNotEmpty:boolean;
    textColor: string; //文字颜色
    year: integer; //年
    visible: boolean; //是否可见
    constructor Create(); 
end;

{月层}
type 
  MonthDiv = class
  public
    aDirection: integer; //动画的方向
    aTick: integer; //动画当前帧数
    aTotalTick: integer; //动画总帧数
    isNotEmpty:boolean;
    month: integer; //月份
    year: integer; //年份
    monthButtons:array of MonthButton;
    monthButtons_am:array of MonthButton;
    constructor Create(); 
end;

{年层}
type 
  YearDiv = class
  public
    aDirection: integer; //动画的方向
    aTick: integer; //动画当前帧数
    aTotalTick: integer; //动画总帧数
    isNotEmpty:boolean;
    startYear: integer; //开始年份
    yearButtons:array of YearButton;
    yearButtons_am:array of YearButton;
    constructor Create(); 
end;

{日层}
type 
  DayDiv = class
  public
    aClickRowFrom: integer; //点击时的上月的行
    aClickRowTo: integer; //点击时的当月的行
    aDirection: integer; //动画的方向
    aTick: integer; //动画当前帧数
    aTotalTick: integer; //动画总帧数
    isNotEmpty:boolean;
    dayButtons:array of DayButton;
    dayButtons_am:array of DayButton;
    constructor Create(); 
end;

{头部层}
type 
  HeadDiv = class
  public
    arrowColor: string; //箭头颜色
    backColor: string; //箭头颜色
    bounds: FCRect; //显示区域
    isNotEmpty:boolean;
    textColor: string; //文字颜色
    titleFont: string; //标题字体
    weekFont: string; //星期字体
    constructor Create(); 
end;

{时间层}
type 
  TimeDiv = class
  public
    bounds: FCRect; //显示区域
    isNotEmpty:boolean;
    constructor Create(); 
end;

{日历}
type 
  FCCalendar = class(FCView)
  public
    dDiv: DayDiv; //日层
    hDiv: HeadDiv; //头部层
    mDiv: MonthDiv; //月层
    mode: string; //模式
    selectedDay: CDay; //选中日
    tDiv: TimeDiv; //时间层
    useAnimation: boolean; //是否使用动画
    yDiv: YearDiv; //年层
    years:array of CYear;
    constructor Create(); 
end;

type  
  ClickGridCellEventCallBack = procedure(var grid:FCGrid; var row:FCGridRow; var gridColumn:FCGridColumn; var cell:FCGridCell; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
  ClickGridColumnEventCallBack = procedure(var grid:FCGrid; var gridColumn:FCGridColumn; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
  ClickTreeNodeEventCallBack = procedure(var tree:FCTree; var node:FCTreeNode; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
  CalculateChartMaxMinEventCallBack = procedure(var chart:FCChart);
  InvalidateViewEventCallBack = procedure(var inView:FCView);
  InvalidateEventCallBack = procedure(var paint:FCPaint);
  KeyEventCallBack = procedure(var inView:FCView; key:integer);
  MouseEventCallBack = procedure(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);
  ClickEventCallBack = procedure(var inView:FCView; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
  PaintEventCallBack = procedure(var inView:FCView; var paint:FCPaint; clipRect:FCRect);
  PaintGridCellEventCallBack = procedure(var grid:FCGrid; var row:FCGridRow; var column:FCGridColumn; var cell:FCGridCell; var paint:FCPaint; left:double; top:double; right:double; bottom:double);
  PaintGridColumnEventCallBack = procedure(var grid:FCGrid; var column:FCGridColumn; var paint:FCPaint; left:double; top:double; right:double; bottom:double);
  PaintTreeNodeEventCallBack = procedure(var tree:FCTree; var row:FCTreeRow; var column:FCTreeColumn; var node:FCTreeNode; var paint:FCPaint; left:double; top:double; right:double; bottom:double);
  PaintCalendarDayButtonEventCallBack = procedure(var calendar:FCCalendar; var dButton:DayButton; var paint:FCPaint);
  PaintCalendarMonthButtonEventCallBack = procedure(var calendar:FCCalendar; var mButton:MonthButton; var paint:FCPaint);
  PaintCalendarYearButtonEventCallBack = procedure(var calendar:FCCalendar; var yButton:YearButton; var paint:FCPaint);
  PaintCalendarHeadDivEventCallBack = procedure(var calendar:FCCalendar; var hDiv:HeadDiv; var paint:FCPaint);
  RenderViewsEventCallBack = procedure(var views: viewArray; var paint:FCPaint; clipRect:FCRect);
  UpdateViewEventCallBack = procedure(var views:viewArray);
  ContainsPointCallBack = function(var inView:FCView; mp:FCPoint):boolean;

var gViews:viewArray;
var draggingView: FCView; //正被拖动的控件   
var focusedView: FCView; //焦点视图
var touchDownView: FCView; //鼠标按下的视图
var touchMoveView: FCView; //鼠标移动的视图
var OnPaintEvent:PaintEventCallBack;
var OnPaintBorderEvent:PaintEventCallBack;
var OnMouseDownEvent:MouseEventCallBack;
var OnMouseUpEvent:MouseEventCallBack;
var OnMouseMoveEvent:MouseEventCallBack;
var OnMouseWheelEvent:MouseEventCallBack;
var UpdateViewEvent:UpdateViewEventCallBack;
var OnClickEvent:ClickEventCallBack;
var OnKeyDownEvent:KeyEventCallBack;
var OnKeyUpEvent:KeyEventCallBack;
var OnCharEvent:KeyEventCallBack;
var OnContainsPointEvent:ContainsPointCallBack;

{添加顶层视图
inView 视图
paint 绘图对象}
procedure AddView(var inView:FCView; var paint:FCPaint);

{添加到父视图
inView 视图
parent 父视图}
procedure AddViewToParent(var inView:FCView; var parent:FCView);

{插入到顶层视图
inView 视图
paint 绘图对象
idx 索引}
procedure InsertView(var inView:FCView; var paint:FCPaint; idx:integer);

{插入到到父视图
inView 视图
parent 父视图
idx 索引}
procedure InsertViewToParent(var inView:FCView; var parent:FCView; idx:integer);

{清除输入框
views:视图集合}
procedure ClearViewInputs(var views:viewArray);

{移除所有视图
paint 绘图对象}
procedure ClearViews(var paint:FCPaint);

{移除顶层视图
inView 视图
paint 绘图对象}
procedure RemoveView(var inView:FCView; var paint:FCPaint);

{从父视图中移除
inView 视图
parent 父视图}
procedure RemoveViewFromParent(var inView:FCView; var parent:FCView);

{获取绝对位置X
inView:视图}
function ClientX(var inView:FCView):double;

{获取绝对位置Y
inView:视图}
function ClientY(var inView:FCView):double;

{是否包含坐标
inView:视图
mp:坐标}
function ContainsPoint(var inView:FCView; mp:FCPoint):boolean;

{根据名称查找视图
viewName:名称
views:视图集合}
function FindViewByName(viewName:string; var views:viewArray):FCView;

{根据坐标查找视图
mp:坐标
views:视图集合}
function FindView(mp:FCPoint; var views:viewArray):FCView;

{是否重绘时可见
inView:视图}
function IsPaintVisible(var inView:FCView):boolean;

{是否可用
inView:视图}
function IsViewEnabled(var inView:FCView):boolean;

{获取区域的交集}
function GetIntersectRect(var lpDestRect:FCRect; var lpSrc1Rect:FCRect; var lpSrc2Rect:FCRect) :integer;

{获取格式化日期}
function GetFormatDate(num:double; formatStr:string):string;

{重绘复选按钮
checkBox:视图
paint:绘图对象
clipRect:裁剪区域}
procedure DrawCheckBox(var checkBox:FCCheckBox; var paint:FCPaint; clipRect:FCRect);

{重绘单选按钮
radioButton:视图
paint:绘图对象
clipRect:裁剪区域}
procedure DrawRadioButton(var radioButton:FCRadioButton; var paint:FCPaint; clipRect:FCRect);

{重绘按钮
button:视图
paint:绘图对象
clipRect:裁剪区域}
procedure DrawButton(var button:FCView; var paint:FCPaint; clipRect:FCRect);

{点击复选按钮
checkBox:视图
mp:坐标}
procedure ClickCheckBox(var checkBox:FCCheckBox; mp:FCPoint);

{点击单选按钮
radioButton:视图
mp:坐标}
procedure ClickRadioButton(var radioButton:FCRadioButton; mp:FCPoint);

{获取月的日数
year:年
month:月}
function GetDaysInMonth(year:integer; month:integer):integer;

{根据字符获取月份
month:月}
function GetMonthStr(month:integer):string;

{获取年
years:年的集合
year:年}
function GetYear(var calendar:FCCalendar; year:integer):CYear;

{显示隐藏日期层
dDiv:日期层
visible:是否可见}
procedure ShowOrHideDayDiv(var dDiv:DayDiv; visible:boolean);

{显示隐藏日期层
mDiv:月层
visible:是否可见}
procedure ShowOrHideMonthDiv(var mDiv:MonthDiv; visible:boolean);

{显示隐藏日期层
yDiv:年层
visible:是否可见}
procedure showOrHideYearDiv(var yDiv:YearDiv; visible:boolean);

{初始化日历
calendar:日历}
procedure InitCalendar(var calendar:FCCalendar);

{获取星期
y:年
m:月
d:日}
function DayOfWeek(y:integer; m:integer; d:integer):integer;

{获取当月
calendar:日历}
function GetMonth(var calendar:FCCalendar):CMonth;

{获取下个月
calendar:日历
year:年
month:月}
function GetNextMonth(var calendar:FCCalendar; year:integer; month:integer):CMonth;

{获取上个月
calendar:日历
year:年
month:月}
function GetLastMonth(var calendar:FCCalendar; year:integer; month:integer):CMonth;

{重置日期层布局
calendar:日历
dDiv:日期层
state:状态}
procedure ResetDayDiv(var calendar:FCCalendar; var dDiv:DayDiv; state:integer);

{重置月层布局
calendar:日历
mDiv:月层
state:状态}
procedure ResetMonthDiv(var calendar:FCCalendar; var mDiv:MonthDiv; state:integer);

{重置年层布局
calendar:日历
yDiv:年层
state:状态}
procedure ResetYearDiv(var calendar:FCCalendar; var yDiv:YearDiv; state:integer);

{选择开始年份
calendar:日历
yDiv:年层
startYear:开始年}
procedure SelectStartYear(var calendar:FCCalendar; var yDiv:YearDiv; startYear:integer);

{选择年份
calendar:日历
mDiv:月层
year:年}
procedure SelectYear(var calendar:FCCalendar; var mDiv:MonthDiv; year:integer);

{更新日历的布局
calendar:日历}
procedure UpdateCalendar(var calendar:FCCalendar);

{绘制头部层
calendar:日历
hDiv:头部层
paint:绘图对象}
procedure DrawHeadDiv(var calendar:FCCalendar; var hDiv:HeadDiv; var paint:FCPaint);

{绘制日的按钮
calendar:日历
dButton:日期按钮
paint:绘图对象}
procedure DrawDayButton(var calendar:FCCalendar; var dButton:DayButton; var paint:FCPaint);

{绘制月的按钮
calendar:日历
mButton:月按钮
paint:绘图对象}
procedure DrawMonthButton(var calendar:FCCalendar; var mButton:MonthButton; var paint:FCPaint);

{绘制年的按钮
calendar:日历
yButton:年按钮
paint:绘图对象}
procedure DrawYearButton(var calendar:FCCalendar; var yButton:YearButton; var paint:FCPaint);

{绘制日历
calendar:日历
paint:绘图对象}
procedure DrawCalendar(var calendar:FCCalendar; var paint:FCPaint);

{获取内容的宽度
divView:图层}
function GetDivContentWidth(var divView:FCView):double;

{获取内容的高度
divView:图层}
function GetDivContentHeight(var divView:FCView):double;

{绘制滚动条
divView:图层
paint:绘图对象
clipRect:裁剪区域}
procedure DrawDivScrollBar(var divView:FCView; var paint:FCPaint; clipRect:FCRect);

{图层的鼠标移动方法
divView: 图层
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchMoveDiv(var divView:FCView; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint);

{图层的鼠标按下方法
divView: 图层
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchDownDiv(var divView:FCView; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{图层的鼠标抬起方法
divView: 图层
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchUpDiv(var divView:FCView; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{图层的鼠标滚轮方法
divView:图层
delta:滚轮值}
procedure TouchWheelDiv(var divView:FCView; delta:integer);

{重绘图层
divView: 图层
paint:绘图对象
clipRect:裁剪区域}
procedure DrawDiv(var divView:FCView; var paint:FCPaint; clipRect:FCRect);

{重绘图层边线
divView: 图层
paint:绘图对象
clipRect:裁剪区域}
procedure DrawDivBorder(var divView:FCView; var paint:FCPaint; clipRect:FCRect);

{快速添加表格列
grid:表格
columns:列名集合}
procedure FastAddGridColumns(var grid:FCGrid; var columns:array of string);

{快速添加表格行
grid:表格
datas:数据集合}
function FastAddGridRow(var grid:FCGrid; var datas:array of string):FCGridRow;

{添加视图到单元格
inView:视图
cell:单元格
grid:表格}
procedure AddViewToGridCell(var inView:FCView; var cell:FCGridCell; var grid:FCGrid);

{获取内容的宽度
grid:表格}
function GetGridContentWidth(var grid:FCGrid):double;

{获取内容的高度
grid:表格}
function GetGridContentHeight(var grid:FCGrid):double;

{绘制单元格
grid:表格
row:行
column:列
cell:单元格
paint:绘图对象
left:左侧坐标
top:上方坐标
right:右侧坐标
bottom:下方坐标}
procedure DrawGridCell(var grid:FCGrid; var row:FCGridRow; var column:FCGridColumn; var cell:FCGridCell; var paint:FCPaint; left:double; top:double; right:double; bottom:double);

{绘制列
grid:表格
column:列
paint:绘图对象
left:左侧坐标
top:上方坐标
right:右侧坐标
bottom:下方坐标}
procedure DrawGridColumn(var grid:FCGrid; var column:FCGridColumn; var paint:FCPaint; left:double; top:double; right:double; bottom:double);

{绘制表格
grid:表格
paint:绘图对象
clipRect:裁剪区域}
procedure DrawGrid(var grid:FCGrid; var paint:FCPaint; clipRect:FCRect);

{绘制表格的滚动条
grid:表格
paint:绘图对象
clipRect:裁剪区域}
procedure DrawGridScrollBar(var grid:FCGrid; var paint:FCPaint; clipRect:FCRect);

{表格的鼠标移动方法
grid: 表格
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchMoveGrid(var grid:FCGrid; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint);

{表格的鼠标按下方法
grid: 表格
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchDownGrid(var grid:FCGrid; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{表格的鼠标抬起方法
grid: 表格
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchUpGrid(var grid:FCGrid; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{表格的鼠标滚轮方法
grid:表格
delta:滚轮值}
procedure TouchWheelGrid(var grid:FCGrid; delta:integer);

{重置分割线的布局
split:分割视图}
procedure ResetSplitLayoutDiv(var split:FCSplitLayoutDiv);

{重置布局图层 
layout:布局层}
procedure ResetLayoutDiv(var layout:FCLayoutDiv);

{更新页的布局
tabView:多页夹
tabPage:页
left:左侧坐标
top:上方坐标
width:宽度
height:高度
tw:页头按钮的宽度
th:页头按钮的高度}
procedure UpdataPageLayout(var tabView:FCTabView; tabPage:FCTabPage; left:double;
    top:double; width:double; height:double; tw:double; th:double);

{更新多页夹的布局
tabView:多页夹}
procedure UpdateTabLayout(var tabView:FCTabView);

{添加页
tabView:多页夹
tabPage:页
tabButton:页头按钮}
procedure AddTabPage(var tabView:FCTabView; var tabPage:FCTabPage; var tButton:FCView);

{移除页
tabView:多页夹
tabPage:页}
procedure RemoveTabPage(var tabView:FCTabView; var tabPage:FCTabPage);

{选中页
tabView:多页夹
tabPage:页}
procedure SelectTabPage(var tabView:FCTabView; var tabPage:FCTabPage);

{重绘多页加
tabView:多页夹
paint:绘图对象
clipRect:裁剪区域}
procedure DrawTabViewBorder(var tabView:FCTabView; var paint:FCPaint; clipRect:FCRect);

{获取内容的宽度
tree:树}
function GetTreeContentWidth(var tree:FCTree):double;

{获取内容的高度
tree:树}
function GetTreeContentHeight(var tree:FCTree):double;

{获取总的偏移量
node:树节点}
function GetTotalIndent(var node:FCTreeNode):double;

{绘制单元格
tree:树
row:行
column:列
node:节点
paint:绘图对象
left:左侧坐标
top:上方坐标
right:右侧坐标
bottom:下方坐标}
procedure DrawTreeNode(var tree:FCTree; var row:FCTreeRow; var column:FCTreeColumn; var node:FCTreeNode; var paint:FCPaint; left:double; top:double; right:double; bottom:double);

{绘制树
tree:树
paint:绘图对象
clipRect:裁剪区域}
procedure DrawTree(var tree:FCTree; var paint:FCPaint; clipRect:FCRect);

{展开或折叠节点
node:节点
visible:是否可见}
procedure HideOrShowTreeNode(var tree:FCTree; var node:FCTreeNode; visible:boolean);

{选中或反选节点
node:节点
checked:是否选中}
procedure CheckOrUnCheckTreeNode(var node:FCTreeNode; checked:boolean);

{绘制滚动条
tree:树
paint:绘图对象
clipRect:裁剪区域}
procedure DrawTreeScrollBar(var tree:FCTree; var paint:FCPaint; clipRect:FCRect);

{树的鼠标移动方法
grid: 表格
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchMoveTree(var tree:FCTree; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint);

{树的鼠标按下方法
grid: 表格
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchDownTree(var tree:FCTree; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{树的鼠标滚轮方法
grid:表格
delta:滚轮值}
procedure TouchWheelTree(var tree:FCTree; delta:integer);

{更新行的索引
tree:树}
procedure UpdateTreeRowIndex(var tree:FCTree);

{获取最后一行的索引 
node:树节点}
function GetTreeLastNodeRowIndex(var node:FCTreeNode):integer;

{添加节点
tree:树
node:要添加的节点
parentNode:父节点}
procedure AppendTreeNode(var tree:FCTree; var node:FCTreeNode; var parentNode:FCTreeNode);

{数值转字符串，可以设置保留位数
value 数值
digit 小数位数}
function ToFixed(value:double; digit:integer):string;

{计算直线参数
mp:坐标
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2
oX:坐标起始X
oY:坐标起始Y}
procedure LineXY(var chart:FCChart; x1:double; y1:double; x2:double; y2:double; oX:double; oY:double);

{判断是否选中直线
mp:坐标
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2}
function SelectLine(var chart:FCChart; mp:FCPoint; x1:double; y1:double; x2:double; y2:double):boolean;

{判断是否选中射线
mp:坐标
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2}
function SelectRay(var chart:FCChart; mp:FCPoint; x1:double; y1:double; x2:double; y2:double):boolean;

{判断是否选中线段
mp:坐标
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2}
function SelectSegment(var chart:FCChart; mp:FCPoint; x1:double; y1:double; x2:double; y2:double):boolean;

{根据三点计算圆心
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2
x3:横坐标3
y3:纵坐标3}
procedure EllipseOR(var chart:FCChart; x1:double; y1:double; x2:double; y2:double; x3:double; y3:double);

{判断点是否在椭圆上
x:横坐标
y:纵坐标
oX:坐标起始X
oY:坐标起始Y
a:椭圆参数a
b:椭圆参数b}
function EllipseHasPoint(ix:Double; iy:Double; oX:Double; oY:Double; a:Double; b:Double):boolean;

{计算线性回归
list:集合}
procedure LinearRegressionEquation(var chart:FCChart; list:DoubleArray);

{计算最大值
list:集合}
function MaxValue(list:DoubleArray):double;

{计算最小值
list:集合}
function MinValue(list:DoubleArray):double;

{计算平均值
list:集合}
function AvgValue(list:DoubleArray):double;

{计算平行四边形参数
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2
x3:横坐标3
y3:纵坐标3}
procedure Parallelogram(var chart:FCChart; x1:double; y1:double; x2:double; y2:double; x3:double; y3:double);

{获取百分比线的刻度 
y1: 纵坐标1 
y2: 纵坐标2}
procedure GetPercentParams(y1:double; y2:double; var list:DoubleArray);

{计算斐波那契数列
idx:索引}
function FibonacciValue(idx:integer):integer;

{根据坐标计算矩形
x1:横坐标1
y1:纵坐标1
x2:横坐标2
y2:纵坐标2}
procedure RectangleXYWH(var chart:FCChart; x1:double; y1:double; x2:double; y2:double);

{计算EMA
n:周期
value:当前数据
lastEMA:上期数据}
function GetEMA(n:integer; value:double; lastEMA:double):double;

{计算MACD
dif:DIF数据
dea:DEA数据}
procedure GetMACD(dif:DoubleArray; dea:DoubleArray; var macd:DoubleArray);

{计算DIF
close12:12日数据
close26:26日数据}
procedure GetDIF(close12:DoubleArray; close26:DoubleArray; var dif:DoubleArray);

{MA数据计算}
procedure MaValue(ticks:DoubleArray; days:integer; var mas:DoubleArray);

{计算最大值}
procedure HHVValue(ticks:DoubleArray; days:integer; var hhv:DoubleArray);

{计算最小值}
procedure LLVValue(ticks:DoubleArray; days:integer; var llv:DoubleArray);

{REF函数}
procedure RefValue(ticks:DoubleArray; days:integer; var refArr:DoubleArray);

{获取TRIX的数据
ticks:数据}
procedure GetTRIXData(ticks:DoubleArray; n:integer; m:integer; var trixArr:DoubleArray; var matrixArr:DoubleArray);

{获取方差数据}
function StandardDeviationSum(listValue:DoubleArray; avgValue:double):double;

{计算boll指标,ma的周期为20日}
procedure GetBollData(ticks:DoubleArray; maDays:integer; var ups:DoubleArray; var mas:DoubleArray; var lows:DoubleArray);

{计算kdj指标,rsv的周期为9日}
procedure GetKDJData(highArr:DoubleArray;lowArr:DoubleArray; closeArr:DoubleArray; n:integer; m1:integer; m2:integer; var ks:DoubleArray; var ds:DoubleArray; var js:DoubleArray);

{计算rsi指标,分别返回以6日，12日，24日为参考基期的RSI值}
procedure GetRSIData(ticks:DoubleArray; n1:integer; n2:integer; n3:integer; var rsi1:DoubleArray; var rsi2:DoubleArray; var rsi3:DoubleArray);

{计算ROC数据}
procedure GetRocData(ticks:DoubleArray; n:integer; m:integer; var roc:DoubleArray; var maroc:DoubleArray);

{获取BIAS的数据}
procedure GetBIASData(ticks:DoubleArray; n1:integer; n2:integer; n3:integer; var bias1Arr:DoubleArray; var bias2Arr:DoubleArray; var bias3Arr:DoubleArray);

{计算BBI(多空指标)}
procedure GetBBIData(ticks:DoubleArray; n1:integer; n2:integer; n3:integer; n4:integer; var bbiArr:DoubleArray);

{计算WR(威廉指标)}
procedure GetWRData(closeArr:DoubleArray; highArr:DoubleArray; lowArr:DoubleArray; n1:integer; n2:integer; var wr1Arr:DoubleArray; var wr2Arr:DoubleArray);

{计算DMA（平均差}
procedure GetDMAData(ticks:DoubleArray; n1:integer; n2:integer; var difArr:DoubleArray; var difmaArr:DoubleArray);

{CCI(顺势指标)计算  CCI（N日）=（TP－MA）÷MD÷0.015}
procedure GetCCIData(highArr:DoubleArray; lowArr:DoubleArray; closeArr:DoubleArray; n:integer; var cciArr:DoubleArray);

{计算最大最小值
chart:图表}
procedure CalculateChartMaxMin(var chart:FCChart);

{根据位置计算索引
chart:图表
mp:坐标}
function GetChartIndex(var chart:FCChart; mp:FCPoint):integer;

{获取最大显示记录条数
chart:图表
hScalePixel:间隔
pureH:横向距离}
function GetChartMaxVisibleCount(var chart:FCChart; hScalePixel:double; pureH:double):integer;

{获取图表层的高度
chart:图表}
function GetCandleDivHeight(var chart:FCChart):double;

{获取成交量层的高度
chart:图表}
function GetVolDivHeight(var chart:FCChart):double;

{获取指标层的高度
chart:图表}
function GetIndDivHeight(var chart:FCChart):double;

{获取横向工作区
chart:图表}
function GetChartWorkAreaWidth(var chart:FCChart):double;

{根据索引获取横坐标
chart:图表
idx:索引}
function GetChartX(var chart:FCChart; idx:integer):double;

{根据日期获取索引
chart:图表
date:日期}
function GetChartIndexByDate(var chart:FCChart; date:double):integer;

{根据索引获取日期
chart:图表
idx:索引}
function GetChartDateByIndex(var chart:FCChart; idx:integer):double;

{计算数值在层中的位置
chart:图表
divIndex:所在层
chart:数值}
function GetChartY(var chart:FCChart; divIndex:integer; value:double):double;

{计算数值在层中的右轴位置
chart:图表
divIndex:所在层
chart:数值}
function GetChartYInRight(var chart:FCChart; divIndex:integer; value:double):double;

{根据坐标获取对应的值
chart:图表
point:坐标}
function GetChartValue(var chart:FCChart; point:FCPoint):double;

{计算线性回归上下限
chart:图表
plot:画线
a:直线k
b:直线b}
procedure GetLRBandRange(var chart:FCChart; var plot:FCPlot; a:double; b:double);

{根据坐标获取对应的值
chart:图表
point:坐标}
function GetCandleDivValue(var chart:FCChart; point:FCPoint):double;

{检查最后可见索引
chart:图表}
procedure CheckChartLastVisibleIndex(var chart:FCChart);

{自动设置首先可见和最后可见的记录号
chart:图表}
procedure ResetChartVisibleRecord(var chart:FCChart);

{设置可见索引
chart:图表
firstVisibleIndex:起始索引
lastVisibleIndex:结束索引}
procedure setChartVisibleIndex(var chart:FCChart; firstVisibleIndex:integer; lastVisibleIndex:integer);

{获取图表的区域
chart: 图表
plot: 画线}
procedure GetCandleRange(var chart:FCChart; plot:FCPlot);

{计算坐标轴
min:最小值
max:最大值
yLen:长度
maxSpan:最大间隔
minSpan:最小间隔
defCount:数量}
procedure ChartGridScale(var chart:FCChart; minValue:double; maxValue:double; yLen:double; maxSpan:double; minSpan:double; defCount:integer);

{缩小
chart:图表}
procedure ZoomOutChart(var chart:FCChart);

{放大
chart:图表}
procedure ZoomInChart(var chart:FCChart);

{清除缓存数据方法
chart:图表}
procedure ClearDataArr(var chart:FCChart);

{获取数据
chart:图表}
procedure CalcChartIndicator(var chart:FCChart);

{判断是否选中线条
chart:图表
mp:坐标
divIndex:层索引
datas:数据
curIndex:当前索引}
function SelectLines(var chart:FCChart; mp:FCPoint; divIndex:integer; datas:DoubleArray; curIndex:integer):boolean;

{判断是否在右轴选中线条
chart:图表
mp:坐标
divIndex:层索引
datas:数据
curIndex:当前索引}
function SelectLinesInRight(var chart:FCChart; mp:FCPoint; divIndex:integer; datas:DoubleArray; curIndex:integer):boolean;

{判断是否选中图形
chart:图表
mp:坐标}
procedure SelectShape(var chart:FCChart; mp:FCPoint);

{选中直线
chart: 图表
mp:坐标}
function SelectPlot(var chart:FCChart; mp:FCPoint):FCPlot;

{绘制刻度
chart:图表
paint:绘图对象
clipRect:裁剪区域}
procedure DrawChartScale(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);

{绘制十字线
chart:图表
paint:绘图对象
clipRect:裁剪区域}
procedure DrawChartCrossLine(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);

{绘制线条
chart:图表
paint:绘图对象
clipRect:裁剪区域
divIndex:图层
datas:数据
color:颜色
selected:是否选中}
procedure DrawChartLines(var chart:FCChart; var paint:FCPaint; clipRect:FCRect; divIndex:integer; datas:DoubleArray; color:String; selected:boolean);

{绘制线条到右轴
chart:图表
paint:绘图对象
clipRect:裁剪区域
divIndex:图层
datas:数据
color:颜色
selected:是否选中}
procedure DrawChartLinesInRight(var chart:FCChart; var paint:FCPaint; clipRect:FCRect; divIndex:integer; datas:DoubleArray; color:String; selected:boolean);

{绘制画线工具
chart:图表
paint:绘图对象
clipRect:裁剪区域}
procedure DrawChartPlot(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);

{绘制图表
chart:图表
paint:绘图对象
clipRect:裁剪区域}
procedure DrawChartStock(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);

{绘制图形
chart:图表
paint:绘图对象
clipRect:裁剪区域}
procedure DrawChart(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);

{重绘背景的实现方法
inView:视图
paint:绘图对象
clipRect:裁剪区域}
procedure OnPaintDefault(var inView:FCView; var paint:FCPaint; clipRect:FCRect);

{重绘边框的实现方法
inView:视图
paint:绘图对象
clipRect:裁剪区域}
procedure OnPaintBorderDefault(var inView:FCView; var paint:FCPaint; clipRect:FCRect);

{重绘视图
views:视图集合
paint:绘图对象
rect:区域}
procedure RenderViews(var views:viewArray; paint:FCPaint; rect:FCRect);

{全局刷新方法
paint:绘图对象}
procedure Invalidate(var paint:FCPaint);

{刷新视图方法
view:视图}
procedure InvalidateView(var inView:FCView);

{隐藏视图
mp 坐标
paint 绘图对象}
procedure AutoHideView(mp:FCPoint; paint:FCPaint);

{日历的秒表
calendar:日历}
procedure CalendarTimer(var calendar:FCCalendar);

{点击日的按钮
calendar:日历
dButton:日期按钮
mp:坐标}
procedure ClickDayButton(var calendar:FCCalendar; var dButton:DayButton; mp:FCPoint);

{点击月的按钮
calendar:日历
mButton:月按钮
mp:坐标}
procedure ClickMonthButton(var calendar:FCCalendar; var mButton:MonthButton; mp:FCPoint);

{点击年的按钮
calendar:日历
yButton:年按钮
mp:坐标}
procedure ClickYearButton(var calendar:FCCalendar; var yButton:YearButton; mp:FCPoint);

{点击左侧的按钮
calendar:日历
hDiv:头部层
mp:坐标}
procedure ClickLastButton(var calendar:FCCalendar; var hDiv:HeadDiv; mp:FCPoint);

{点击右侧的按钮
calendar:日历
hDiv:头部层
mp:坐标}
procedure ClickNextButton(var calendar:FCCalendar; var hDiv:HeadDiv; mp:FCPoint);

{改变模式的按钮
calendar:日历
hDiv:头部层
mp:坐标}
procedure ClickModeButton(var calendar:FCCalendar; var hDiv:HeadDiv; mp:FCPoint);

{点击日历
calendar:日历
mp:坐标}
procedure ClickCalendar(var calendar:FCCalendar; mp:FCPoint);

{树的鼠标抬起方法
grid: 表格
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchUpTree(var tree:FCTree; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{图表的鼠标按下方法
chart: 图表
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchDownChart(var chart:FCChart; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint);

{添加画线
chart: 图表
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure AddPlotDefault(var chart:FCChart; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint);

{图表的鼠标移动方法
chart: 图表
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标}
procedure TouchMoveChart(var chart:FCChart; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint);

{鼠标按下的方法
inView:视图
mp:坐标
buttons:按钮
clicks:点击次数
delta:滚轮值}
procedure OnMouseDownDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);

{鼠标抬起的方法
inView:视图
mp:坐标
buttons:按钮
clicks:点击次数
delta:滚轮值}
procedure OnMouseUpDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);

{鼠标移动的方法
inView:视图
mp:坐标
buttons:按钮
clicks:点击次数
delta:滚轮值}
procedure OnMouseMoveDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);

{鼠标点击的方法
inView:视图
firstTouch:是否第一次触摸
firstPoint:第一次触摸的坐标
secondTouch:是否第二次触摸
secondPoint:第二次触摸的坐标
clicks:点击次数}
procedure OnClickDefault(var inView:FCView; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint; clicks:integer);

{视图的鼠标滚动方法
view 视图
mp 坐标
buttons 按钮 0未按下 1左键 2右键
clicks 点击次数
delta 滚轮值}
procedure OnMouseWheelDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);

{视图的键盘按下方法
view 视图
value 按键值}
procedure OnKeyDownDefault(var inView:FCView; value:integer);

{视图的键盘抬起方法
view 视图
value 按键值}
procedure OnKeyUpDefault(var inView:FCView; value:integer);

{视图的键盘输入方法
view 视图
value 按键值}
procedure OnCharDefault(var inView:FCView; value:integer);

{更新悬浮状态
views:视图集合}
procedure UpdateViewDefault(var views:viewArray);

{视图尺寸改变}
procedure WindowResize(var rect:FCRect; resizePoint:integer; nowPoint:FCPoint; startTouchPoint:FCPoint);

{获取调整尺寸的点}
function GetResizeState(var inView:FCView; mp:FCPoint):integer;

{鼠标滚动方法
mp 坐标
buttons 按钮 0未按下 1左键 2右键
clicks 点击次数
delta 滚轮值
paint 绘图对象}
procedure HandleMouseWheel(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);

{鼠标按下方法
mp 坐标
buttons 按钮 0未按下 1左键 2右键
clicks 点击次数
delta 滚轮值
paint 绘图对象}
procedure HandleMouseDown(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);

{鼠标抬起方法
mp 坐标
buttons 按钮 0未按下 1左键 2右键
clicks 点击次数
delta 滚轮值
paint 绘图对象}
procedure HandleMouseUp(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);

{鼠标移动方法
mp 坐标
buttons 按钮 0未按下 1左键 2右键
clicks 点击次数
delta 滚轮值
paint 绘图对象}
procedure HandleMouseMove(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);

{设置属性
inView:视图
node:xml节点}
procedure SetAttributeDefault(var inView:FCView; node:integer);

{读取Xml
paint 绘图对象
node节点
parent 父视图}
procedure ReadXmlNodeDefault(var paint:FCPaint; node:integer; var parent:FCView);

{加载图形界面
paint:绘图对象
xml:Xml内容}
procedure RenderFaceCat(var paint:FCPaint; xmlPath:string);

{Windows消息循环}
procedure WndProcDefault(var paint:FCPaint; hWnd:integer; message:integer; wParam:integer; lParam:integer); 

implementation

constructor FCPoint.Create(inx, iny: double);  
begin  
  x := inx;
  y := iny;
  isNotEmpty := true;
end;

constructor FCSize.Create(icx, icy: double);  
begin  
  cx := icx;
  cy := icy;
  isNotEmpty := true;
end;

constructor FCRect.Create(ileft, itop, iright, ibottom: double);  
begin  
  left := ileft;
  top := itop;
  right := iright;
  bottom := ibottom;
  isNotEmpty := true;
end;

constructor FCPadding.Create(ileft, itop, iright, ibottom: double);  
begin  
  left := ileft;
  top := itop;
  right := iright;
  bottom := ibottom;
end;

constructor FCPaint.Create();  
begin
  cancelClick := false;
  defaultUIStyle := 'light'; 
  dragBeginPoint.Create(0, 0);
  dragBeginRect.Create(0, 0, 0, 0);
  gID := 0;
  hWnd := 0;
  isDoubleClick := false;
  isNotEmpty := true;
  offsetX := 0;
  offsetY := 0; 
  resizeColumnState := 0; 
  resizeColumnBeginWidth := 0; 
  resizeColumnIndex := -1; 
  scaleFactorX := 1; 
  scaleFactorY := 1; 
  size.Create(0, 0); 
  systemFont := 'Arial'; 
  touchDownPoint.Create(0, 0);
end;

{开始绘图 
rect:区域}
procedure FCPaint.BeginPaint(rect:FCRect; pRect:FCRect);
begin
  BeginPaintGdiPlus2(gID, trunc(rect.left), trunc(rect.top), trunc(rect.right), trunc(rect.bottom), trunc(pRect.left), trunc(pRect.top), trunc(pRect.right), trunc(pRect.bottom));
end;

{绘制线
color:颜色 
width:宽度 
style:样式 
x1:横坐标1 
y1:纵坐标1 
x2:横坐标2 
y2:纵坐标2}
procedure FCPaint.DrawLine(color:string; width:integer; style:integer; x1:double; y1:double; x2:double; y2:double);
var
  inStyle:integer;
begin
	inStyle := trunc(style);
  DrawLineGdiPlus(gID, ToColorGdiPlus(color), width, inStyle, trunc(x1), trunc(y1), trunc(x2), trunc(y2));
end;

{绘制连续线
color:颜色 
width:宽度 
style:样式 
apt:坐标集合}
procedure FCPaint.DrawPolyline(color:string; width:integer; style:integer; apt:array of FCPoint);
var
  inStyle:integer;
  strApt:string;
  i:integer;
  aptLength:integer;
  pStr:PChar;
begin
	inStyle := trunc(style);
  aptLength := High(apt) - Low(apt) + 1;
  if aptLength = 1 then
  begin
    DrawLine(color, width, style, apt[0].x, apt[0].y, apt[0].x, apt[0].y)
  end
  else
  begin
    for i := 0 to aptLength - 1 do
    begin
      strApt := strApt + IntToStr(trunc(apt[i].x)) + ',' + IntToStr(trunc(apt[i].y));
      if i <> aptLength - 1 then
        strApt := strApt + ' ';
    end;
    pStr := PChar(strApt);
    DrawPolylineGdiPlus(gID, ToColorGdiPlus(color), width, inStyle, pStr);
  end;
end;

{绘制多边形
color:颜色 
width:宽度 
style:样式 
apt:坐标集合}
procedure FCPaint.DrawPolygon(color:string; width:integer; style:integer; apt:array of FCPoint);
var
  inStyle:integer;
  strApt:string;
  i:integer;
  aptLength:integer;
  pStr:PChar;
begin
	inStyle := trunc(style);
  aptLength := High(apt) - Low(apt) + 1;
  for i := 0 to aptLength - 1 do
  begin
    strApt := strApt + IntToStr(trunc(apt[i].x)) + ',' + IntToStr(trunc(apt[i].y));
    if i <> aptLength - 1 then
      strApt := strApt + ' ';
  end;
  pStr := PChar(strApt);
  DrawPolygonGdiPlus(gID, ToColorGdiPlus(color), width, inStyle, pStr);
end;

{绘制矩形 
color:颜色 
width:宽度 
style:样式 
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标}
procedure FCPaint.DrawRect(color:string; width:integer; style:integer; left:double; top:double; right:double; bottom:double);
var
  inStyle:integer;
begin
	inStyle := trunc(style);
  DrawRectGdiPlus(gID, ToColorGdiPlus(color), width, inStyle, trunc(left), trunc(top), trunc(right), trunc(bottom));
end;

{绘制圆角矩形 
color:颜色 
width:宽度 
style:样式 
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标
cornerRadius:圆角}
procedure FCPaint.DrawRoundRect(color:string; width:integer; style:integer; left:double; top:double; right:double; bottom:double; cornerRadius:double);
var
  inStyle:integer;
begin
	inStyle := trunc(style);
  DrawRoundRectGdiPlus(gID, ToColorGdiPlus(color), width, inStyle, trunc(left), trunc(top), trunc(right), trunc(bottom), trunc(cornerRadius));
end;

{绘制椭圆
color:颜色 
width:宽度 
style:样式 
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标}
procedure FCPaint.DrawEllipse(color:string; width:integer; style:integer; left:double; top:double; right:double; bottom:double);
var
  inStyle:integer;
begin
	inStyle := trunc(style);
  DrawEllipseGdiPlus(gID, ToColorGdiPlus(color), width, inStyle, trunc(left), trunc(top), trunc(right), trunc(bottom));
end;

{绘制文字大小 
text:文字 
color:颜色 
font:字体 
x:横坐标 
y:纵坐标}
procedure FCPaint.DrawText(text:string; color:string; font:string; x:double; y:double);
var
  pText:PChar;
  pFont:PChar;
begin
  pText := PChar(text);
  pFont := PChar(font);
  DrawTextWithPosGdiPlus2(gID, pText, ToColorGdiPlus(color), pFont, trunc(x), trunc(y));
end;

{绘制矩形 
text文字 
color:颜色 
font:字体 
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:方坐标}
procedure FCPaint.DrawTextAutoEllipsis(text:string; color:string; font:string; left:double; top:double; right:double; bottom:double);
var
  pText:PChar;
  pFont:PChar;
begin
  pText := PChar(text);
  pFont := PChar(font);
  DrawTextWithPosGdiPlus2(gID, pText, ToColorGdiPlus(color), pFont, trunc(left), trunc(top));
end;

{结束绘图}
procedure FCPaint.EndPaint();
begin
  endPaintGdiPlus(gID);
end;

{填充矩形 
color:颜色
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标}
procedure FCPaint.FillRect(color:string; left:double; top:double; right:double; bottom:double);
begin
  FillRectGdiPlus(gID, ToColorGdiPlus(color), trunc(left), trunc(top), trunc(right), trunc(bottom));
end;

{填充矩形 
color:颜色
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标
cornerRadius:圆角}
procedure FCPaint.FillRoundRect(color:string; left:double; top:double; right:double; bottom:double; cornerRadius:double);
begin
  FillRoundRectGdiPlus(gID, ToColorGdiPlus(color), trunc(left), trunc(top), trunc(right), trunc(bottom), trunc(cornerRadius));
end;

{填充多边形 
color:颜色
apt:坐标集合}
procedure FCPaint.FillPolygon(color:string; apt:array of FCPoint);
var
  strApt:string;
  i:integer;
  aptLength:integer;
  pStr:PChar;
begin
  aptLength := High(apt) - Low(apt) + 1;
  for i := 0 to aptLength - 1 do
  begin
    strApt := strApt + IntToStr(trunc(apt[i].x)) + ',' + IntToStr(trunc(apt[i].y));
    if i <> aptLength - 1 then
      strApt := strApt + ' ';
  end;
  pStr := PChar(strApt);
  FillPolygonGdiPlus(gID, ToColorGdiPlus(color), pStr);
end;

{填充椭圆
color:颜色
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标}
procedure FCPaint.FillEllipse(color:string; left:double; top:double; right:double; bottom:double);
begin
  FillEllipseGdiPlus(gID, ToColorGdiPlus(color), trunc(left), trunc(top), trunc(right), trunc(bottom));
end;

{设置偏移量
offsetX:横向偏移 
offsetY:纵向偏移}
procedure FCPaint.SetOffset(x:double; y:double);
begin
  SetOffsetGdiPlus(gID, trunc(x), trunc(y));
end;

{设置裁剪
left:左侧坐标 
top:上方坐标 
right:右侧坐标 
bottom:下方坐标}
procedure FCPaint.SetClip(left:double; top:double; right:double; bottom:double);
begin
  SetClipGdiPlus(gID, trunc(left), trunc(top), trunc(right), trunc(bottom));
end;

{获取字体大小 
text:文字 
font:字体}
function FCPaint.TextSize(text:string;font:string):FCSize;
var
  pText:PChar;
  pFont:PChar;
  width:double;
  height:double;
begin
  pText := PChar(text);
  pFont := PChar(font);
  TextSizeGdiPlus4(gID, pText, pFont, -1);
  width := GetTextSizeWidth();
  height := GetTextSizeHeight();
  TextSize := FCSize.Create(width, height);
end;


constructor FCView.Create();  
begin
  align := 'left'; 
  allowDrag := false; 
  allowResize := false;
  allowDragScroll := false; 
  allowPreviewsEvent := false;
  autoHide := false;
  backColor := 'rgb(255,255,255)'; 
  backImage := '';
  borderColor := 'rgb(150,150,150)'; 
  borderWidth := 1;
  clipRect := FCRect.Create(0, 0, 0, 0);
  cornerRadius := 0; 
  cursor := '';
  displayOffset := true;
  dock := ''; 
  downScrollHButton := false;
  downScrollVButton := false; 
  enabled := true; 
  exView := false;
  font := 'Default,14';
  hoveredColor := 'none';
  hoverScrollHButton := false;
  hoverScrollVButton := false;
  hScrollIsVisible := false;
  isNotEmpty := true;
  location := FCPoint.Create(0, 0); 
  margin := FCPadding.Create(0, 0, 0, 0);
  maximumSize := FCSize.Create(0, 0);
  padding := FCPadding.Create(0, 0, 0, 0); 
  pushedColor := 'rgb(200,200,200)';
  resizePoint := -1;
  scrollV := 0; 
  scrollH := 0;
  scrollSize := 8;
  showHScrollBar := false;
  showVScrollBar := false;
  scrollBarColor := 'rgb(100,100,100)'; 
  scrollBarHoveredColor := 'rgb(42,138,195)'; 
  size := FCSize.Create(100, 20);
  startScrollH := 0; 
  startScrollV := 0; 
  startPoint := FCPoint.Create(0, 0); 
  startRect := FCRect.Create(0, 0, 0, 0);
  tabIndex := 0;
  tabStop := false;
  tag := '';
  text := ''; 
  textColor := 'rgb(0,0,0)';
  topMost := false;
  touchDownTime := 0;
  viewName := '';
  verticalAlign := 'top';
  viewType := '';
  visible := true; 
  vScrollIsVisible := false;
  globalUID := globalUID + 1;
  uid := globalUID;
end;

function FCView.GetParent():FCView;
var
  pLength:integer;
  pView:FCView;
begin
  pLength := High(parent) - Low(parent) + 1;
  if pLength > 0 then
    GetParent := parent[0]
  else
    begin
    pView := FCView.Create();
    pView.isNotEmpty := false;
    pView.uid := -1;
    GetParent := pView;
    end;
end;

function FCView.GetPaint():FCPaint;
var
  pLength:integer;
  pPaint:FCPaint;
begin
  pLength := High(paint) - Low(paint) + 1;
  if pLength > 0 then
    GetPaint := paint[0]
  else
    begin
    pPaint := FCPaint.Create();
    pPaint.isNotEmpty := false;
    GetPaint := pPaint;
    end;
end;

procedure FCView.SetParent(p:FCView);
begin
  SetLength(parent, 1);
  parent[0] := p;
end;

procedure FCView.SetPaint(p:FCPaint);
begin
  SetLength(paint, 1);
  paint[0] := p;
end;

constructor FCButton.Create();  
begin
  inherited Create; 
  viewType := 'button';
end;

constructor FCLabel.Create();  
begin
  inherited Create; 
  backColor := 'none';
  viewType := 'label';
end;

constructor FCDiv.Create();  
begin
  inherited Create; 
  viewType := 'div';
end;

constructor FCTextBox.Create();  
begin
  inherited Create; 
  viewType := 'textbox';
end;

constructor FCTabPage.Create();  
begin
  inherited Create; 
  viewType := 'tabpage';
  visible := false;
end;

constructor FCTabView.Create();  
begin
  inherited Create; 
  animationSpeed := 20; 
  layout := 'top'; 
  underLineColor := 'none'; 
  underLineSize := 0; 
  underPoint := FCPoint.Create(0, 0); 
  useAnimation := false; //是否使用动画
  viewType := 'tabview';
end;

constructor FCCheckBox.Create();  
begin
  inherited Create; 
  buttonSize := FCSize.Create(16, 16);
  checked := false; 
  viewType := 'checkbox';
end;

constructor FCRadioButton.Create();  
begin
  inherited Create; 
  buttonSize := FCSize.Create(16, 16);
  checked := false; 
  groupName := '';
  viewType := 'radiobutton';
end;

constructor FCLayoutDiv.Create();  
begin
  inherited Create; 
  autoWrap := false;
  layoutStyle := 'lefttoright'; 
  viewType := 'layout';
end;

constructor FCSplitLayoutDiv.Create();  
begin
  inherited Create; 
  layoutStyle := 'lefttoright'; 
  oldSize := FCSize.Create(0, 0); 
  splitMode := 'absolutesize'; 
  splitPercent := -1; 
  viewType := 'split';
end;

constructor FCGridColumn.Create();  
begin
  allowSort := true; 
  allowResize := false; 
  backColor := 'rgb(200,200,200)';
  borderColor := 'rgb(150,150,150)'; 
  bounds := FCRect.Create(0, 0, 0, 0); 
  cellAlign := 'left'; 
  colName := ''; 
  colType := ''; 
  font := 'Default,14';
  frozen := false;
  colIndex := -1; 
  isNotEmpty := true;
  sort := 'none'; 
  text := '';
  textColor := 'rgb(50,50,50)'; 
  visible := true; 
  width := 120; 
  widthStr := ''; 
end;

constructor FCGridCell.Create();  
begin
  backColor := 'rgb(255,255,255)'; 
  borderColor := 'rgb(150,150,150)'; 
  colSpan := 1; 
  digit := -1; 
  font := 'Default,14';
  isNotEmpty := true;
  rowSpan := 1; 
  textColor := 'rgb(0,0,0)'; 
  value := ''; 
end;

constructor FCGridRow.Create();  
begin
  isNotEmpty := true;
  rowIndex := -1; 
  selected := false;
  visible := true; 
end;

constructor FCGrid.Create();  
begin
  inherited Create; 
  headerHeight := 30; 
  rowHeight := 30;
  selectedRowColor := 'rgb(125,125,125)'; 
  viewType := 'grid';
  showVScrollBar := true;
  showHScrollBar :=  true;
end;

constructor FCTreeNode.Create();  
begin
  allowCollapsed := true;
  backColor := 'rgb(255,255,255)';
  checked := false; 
  collapsed := false; 
  font := 'Default,14';
  isNotEmpty := true;
  indent := 0; 
  rowIndex := -1;
  textColor := 'rgb(0,0,0)'; 
  value := ''; 
end;

constructor FCTreeColumn.Create();  
begin
  bounds := FCRect.Create(0, 0, 0, 0); 
  colIndex := -1; 
  isNotEmpty := true;
  visible := true; 
  width := 120; 
end;

function FCTreeNode.GetParentNode():FCTreeNode;
var
  pLength:integer;
  pNode:FCTreeNode;
begin
  pLength := High(parentNode) - Low(parentNode) + 1;
  if pLength > 0 then
    GetParentNode := parentNode[0]
  else
    begin
    pNode := FCTreeNode.Create();
    pNode.isNotEmpty := false;
    GetParentNode := pNode;
    end;
end;

procedure FCTreeNode.SetParentNode(p:FCTreeNode);
begin
  SetLength(parentNode, 1);
  parentNode[0] := p;
end;

constructor FCTreeRow.Create();  
begin
  isNotEmpty := true;
  rowIndex := -1; 
  selected := false; 
  visible := true; 
end;

constructor FCTree.Create();  
begin
  inherited Create; 
  checkBoxWidth := 25;
  collapsedWidth := 25; 
  headerHeight := 30; 
  indent := 20; 
  rowHeight := 30; 
  selectedRowColor := 'rgb(125,125,125)'; 
  showCheckBox := false;
  viewType := 'tree';
  showVScrollBar := true;
  showHScrollBar :=  true;
end;

constructor BaseShape.Create();  
begin
  color := 'none'; 
  color2 := 'none'; 
  divIndex := 0; 
  isNotEmpty := true;
  leftOrRight := true; 
  lineWidth := 1; 
  shapeName := ''; 
  shapeType := 'line'; 
  style := ''; 
  text := ''; 
  title := ''; 
  title2 := ''; 
  value := 0;
end;

constructor FCPlot.Create();  
begin
  isNotEmpty := true;
  lineColor := 'rgb(0,0,0)';
  lineWidth := 1; 
  pointColor := 'rgba(0,0,0,120)';
  plotType := 'Line';
  key1 := 0; 
  key2 := 0; 
  key3 := 0; 
  startKey1 := 0; 
  startValue1 := 0;
  startKey2 := 0; 
  startValue2 := 0;
  startKey3 := 0; 
  startValue3 := 0; 
  value1 := 0; 
  value2 := 0;
  value3 := 0;
  globalUID := globalUID + 1;
  uid := globalUID;
end;

constructor FCChart.Create();  
begin
  inherited Create; 
  allowDragScroll := true;
  autoFillHScale := false; 
  allowDragChartDiv := false; 
  candleDistance := 0; 
  candleMax := 0; 
  candleMin := 0;
  candleMaxRight := 0;
  candleMinRight := 0; 
  crossTipColor := 'rgb(50,50,50)'; 
  crossLineColor := 'rgb(100,100,100)';
  candlePaddingTop := 30; 
  candlePaddingBottom := 30;
  candleDigit := 2; 
  candleDivPercent := 0.5; 
  crossStopIndex := -1;
  cycle := 'day';
  downColor := 'rgb(15,193,118)'; 
  firstVisibleIndex := -1;
  gridColor := 'rgb(150,150,150)';
  lastVisibleIndex := -1;
  leftVScaleWidth := 80;
  lastRecordIsVisible := true; 
  lastVisibleKey := 0;
  hScalePixel := 11;
  hScaleHeight := 30; 
  hScaleTextDistance := 10; 
  hScaleFormat := ''; 
  indMax := 0; 
  indMin := 0; 
  indMaxRight := 0; 
  indMinRight := 0; 
  indDigit := 2; 
  indDivPercent := 0.3; 
  indPaddingTop := 20; 
  indPaddingBottom := 20;
  lastValidIndex := -1;
  lineWidthChart := 1;
  mainIndicator := ''; 
  magnitude := 1; 
  midColor := 'none';
  offsetX := 0;
  plotPointSizeChart := 5;
  rightVScaleWidth := 0; 
  rightSpace := 0; 
  sPlot := FCPlot.Create();
  sPlot.uid := -1;
  sPlot.isNotEmpty := false;
  scaleColor := 'rgb(100,100,100)'; 
  showIndicator := ''; 
  showCrossLine := false; 
  selectPlotPoint := -1;
  startMovePlot := false; 
  selectShape := ''; 
  selectShapeEx := ''; 
  targetOldX := 0;
  targetOldX2 := 0;
  touchPosition := FCPoint.Create(0, 0);
  trendColor := 'rgb(0,0,0)'; 
  volMax := 0;
  volMin := 0;
  volMaxRight := 0;
  volMinRight := 0;
  volDigit := 0; 
  volDivPercent := 0.2; 
  volPaddingTop := 20;
  volPaddingBottom := 0; 
  vScaleDistance := 35;
  vScaleType := 'standard'; 
  upColor := 'rgb(219,68,83)'; 
  kChart := 0;
  bChart := 0;
  oXChart := 0;
  oYChart := 0;
  rChart := 0;
  candleStyle := 'rect';
  barStyle := 'rect';
  vScaleTextColor := 'none';
  hScaleTextColor := 'none';
  gridStepChart := 0; 
  gridDigitChart := 0;
  firstIndexCacheChart := -1;
  firstTouchIndexCacheChart := -1;
  firstTouchPointCacheChart := FCPoint.Create(0, 0);
  lastIndexCacheChart := -1;
  secondTouchIndexCacheChart := -1;
  secondTouchPointCacheChart := FCPoint.Create(0, 0);
  firstPaddingTop := 0;
  firstPaddingBottom := 0;
  touchDownPointChart := FCPoint.Create(0, 0);
  addingPlotChart := '';
  x4Chart := 0;
  y4Chart := 0;
  nHighChart := 0;
  nLowChart := 0;
  xChart := 0;
  yChart := 0;
  wChart := 0;
  hChart := 0;
  upSubValue := 0;
  downSubValue := 0;
  viewType := 'chart';
end;

constructor CDay.Create();  
begin
  day := 0;
  isNotEmpty := true;
  year := 0;
  month := 0;
end;

constructor CYear.Create();  
begin
  isNotEmpty := true;
  year := 0;
end;

constructor CMonth.Create();  
begin
  isNotEmpty := true;
  year := 0;
  month := 0;
end;

constructor DayButton.Create();  
begin
  backColor := 'none';
  borderColor := 'rgb(150,150,150)'; 
  bounds := FCRect.Create(0, 0, 0, 0); 
  day := CDay.Create();
  font := 'Default,16'; 
  isNotEmpty := true;
  inThisMonth := false; 
  selected := false;
  textColor := 'rgb(0,0,0)'; 
  textColor2 := 'rgb(50,50,50)'; 
  visible := true; 
end;

constructor MonthButton.Create();  
begin
  backColor := 'none'; 
  borderColor := 'rgb(150,150,150)'; 
  bounds := FCRect.Create(0, 0, 0, 0); 
  font := 'Default,16'; 
  isNotEmpty := true;
  month := 0; 
  textColor := 'rgb(0,0,0)'; 
  visible := true; 
  year := 0; //年
end;

constructor YearButton.Create();  
begin
  backColor := 'none'; 
  borderColor := 'rgb(150,150,150)'; 
  bounds := FCRect.Create(0, 0, 0, 0); 
  font := 'Default,16'; 
  isNotEmpty := true;
  textColor := 'rgb(0,0,0)'; 
  visible := true; 
  year := 0; //年
end;

constructor MonthDiv.Create();  
begin
  aDirection := 0;
  aTick := 0;
  aTotalTick := 40; 
  isNotEmpty := true;
  month := 0; 
  year := 0;
  SetLength(monthButtons, 12);
  SetLength(monthButtons_am, 12);
end;

constructor HeadDiv.Create();  
begin
  arrowColor := 'rgb(150,150,150)'; 
  backColor := 'rgb(255,255,255)';
  bounds := FCRect.Create(0, 0, 0, 0); 
  isNotEmpty := true;
  textColor := 'rgb(0,0,0)';
  titleFont := 'Default,20'; 
  weekFont := 'Default,14'; 
end;

constructor YearDiv.Create();  
begin
  aDirection := 0;
  aTick := 0;
  aTotalTick := 40; 
  isNotEmpty := true;
  startYear := 0; 
  SetLength(yearButtons, 12);
  SetLength(yearButtons_am, 12);
end;

constructor DayDiv.Create();  
begin
  aDirection := 0;
  aTick := 0;
  aTotalTick := 40; 
  aClickRowFrom := 0; 
  aClickRowTo := 0; 
  isNotEmpty := true;
  SetLength(dayButtons, 42);
  SetLength(dayButtons_am, 42);
end;

constructor TimeDiv.Create();  
begin
  bounds := FCRect.Create(0, 0, 0, 0); 
  isNotEmpty := true;
end;

constructor FCCalendar.Create();  
begin
  inherited Create; 
  mode := 'day'; 
  viewType := 'calendar';
  dDiv := DayDiv.Create();
  hDiv := HeadDiv.Create();
  mDiv := MonthDiv.Create();
  selectedDay := CDay.Create();
  tDiv := TimeDiv.Create();
  yDiv := YearDiv.Create();
end;

function ToColorGdiPlus(strColor:string):longint;
var
  rStr:PChar;
begin
  rStr := PChar(strColor);
  ToColorGdiPlus := StrToColor(rStr);
end;

procedure AddView(var inView:FCView; var paint:FCPaint);
var
pLength:integer;
begin
  pLength := High(gViews) - Low(gViews) + 1;
  SetLength(gViews, pLength + 1);
  gViews[pLength] := inView;
  inView.SetPaint(paint);
end;

procedure AddViewToParent(var inView:FCView; var parent:FCView);
var
pLength:integer;
begin
  pLength := High(parent.views) - Low(parent.views) + 1;
  SetLength(parent.views, pLength + 1);
  parent.views[pLength] := inView;
  inView.SetPaint(parent.GetPaint());
  inView.SetParent(parent);
end;

procedure InsertView(var inView:FCView; var paint:FCPaint; idx:integer);
var
pLength:integer;
i:integer;
newViews:viewArray;
begin
  pLength := High(gViews) - Low(gViews) + 1;
  SetLength(newViews, pLength + 1);
  for i := 0 to pLength do
  begin
    if i < idx then
      newViews[i] := gViews[i]
    else if i = idx then
      newViews[i] := inView
    else 
      newViews[i] := gViews[i - 1];
  end;
  gViews := newViews;
  inView.SetPaint(paint);
end;

procedure InsertViewToParent(var inView:FCView; var parent:FCView; idx:integer);
var
pLength:integer;
i:integer;
newViews:viewArray;
begin
  pLength := High(parent.views) - Low(parent.views) + 1;
  SetLength(newViews, pLength + 1);
  for i := 0 to pLength do
  begin
    if i < idx then
      newViews[i] := parent.views[i]
    else if i = idx then
      newViews[i] := inView
    else 
      newViews[i] := parent.views[i - 1];
  end;
  parent.views := newViews;
  inView.SetPaint(parent.GetPaint());
  inView.SetParent(parent);
end;

procedure ClearViewInputs(var views:viewArray);
var
  pLength:integer;
  i:integer;
  inView:FCView;
  pName:PChar;
begin
  pLength := High(views) - Low(views) + 1;
  if pLength > 0 then
    begin
    for i := 0 to pLength - 1 do
    begin
      inView := views[i];
      if inView.exView then
        begin
          pName := PChar(inView.viewName);
          removeViewCpp(inView.GetPaint().gID, pName);
        end;
    end;
    end;
end;

procedure ClearViews(var paint:FCPaint);
begin
  ClearViewInputs(gViews);
  SetLength(gViews, 0);
end;

procedure RemoveView(var inView:FCView; var paint:FCPaint);
var
pLength:integer;
i:integer;
newViews:viewArray;
find:boolean;
fView:FCView;
pos:integer;
pName:PChar;
removeViews:viewArray;
begin
  pLength := High(gViews) - Low(gViews) + 1;
  if pLength > 0 then
    begin
    find := false;
    SetLength(newViews, pLength);
    pos := 0;
    for i := 0 to pLength - 1 do
    begin
      fView := gViews[i];
      if fView.uid <> inView.uid then
        begin
        newViews[pos] := gViews[i];
        pos := pos + 1;
        find := true;
        if fView.exView then
        begin
          SetLength(removeViews, 1);
          removeViews[0] := fView;
          ClearViewInputs(removeViews);
        end;
        end;
    end;
    if find then
      begin
      SetLength(newViews, pLength - 1);
      gViews := newViews;
      end;
    end;
end;

procedure RemoveViewFromParent(var inView:FCView; var parent:FCView);
var
pLength:integer;
i:integer;
newViews:viewArray;
find:boolean;
fView:FCView;
pos:integer;
pName:PChar;
removeViews:viewArray;
begin
  pLength := High(parent.views) - Low(parent.views) + 1;
  if pLength > 0 then
    begin
    find := false;
    SetLength(newViews, pLength);
    pos := 0;
    for i := 0 to pLength - 1 do
    begin
      fView := parent.views[i];
      if fView.uid <> inView.uid then
        begin
        newViews[pos] := parent.views[i];
        pos := pos + 1;
        find := true;
        if fView.exView then
        begin
          SetLength(removeViews, 1);
          removeViews[0] := fView;
          ClearViewInputs(removeViews);
        end;
        end;
    end;
    if find then
      begin
      SetLength(newViews, pLength - 1);
      parent.views := newViews;
      end;
    end;
end;

function ClientX(var inView:FCView):double;
var
  cLeft:double;
  pView:FCView;
begin
  if inView.isNotEmpty then
    begin
    cLeft := inView.location.x;
    pView := inView.GetParent();
    if pView.isNotEmpty then
      begin
      if pView.displayOffset and (pView.scrollH <> 0) then
        ClientX := cLeft + ClientX(pView) - pView.scrollH
      else
        ClientX := cLeft + ClientX(pView);
      end
    else
      ClientX := cLeft;
    end
  else
    ClientX := 0;
end;

function ClientY(var inView:FCView):double;
var
  cTop:double;
  pView:FCView;
begin
  if inView.isNotEmpty then
    begin
    cTop := inView.location.y;
    pView := inView.GetParent();
    if pView.isNotEmpty then
      begin
      if pView.displayOffset and (pView.scrollV <> 0) then
        ClientY := cTop + ClientY(pView) - pView.scrollV
      else
        ClientY := cTop + ClientY(pView)
      end
    else
      ClientY := cTop;
    end
  else
    ClientY := 0;
end;

function ContainsPoint(var inView:FCView; mp:FCPoint):boolean;
var
  clx:double;
  cly:double;
  cpx:double;
  cpy:double;
begin
  if IsViewEnabled(inView) then
  begin
    clx := ClientX(inView);
    cly := ClientY(inView);
    cpx := mp.x - clx;
    cpy := mp.y - cly;
    if (cpx >= 0) and (cpx <= inView.size.cx) and (cpy >= 0) and (cpy <= inView.size.cy) then
      ContainsPoint := true
    else
      ContainsPoint := false; 
  end
  else
    ContainsPoint := false; 
end;

function FindViewByName(viewName:string; var views:viewArray):FCView;
var
  viewsLength:integer;
  i:integer;
  vView:FCView;
  subViews:viewArray;
  subViewsLength:integer;
  subView:FCView;
  fView:FCView;
begin
  fView := FCView.Create();
  fView.isNotEmpty := false;
  fView.uid := -1;
  viewsLength := High(views) - Low(views) + 1;
  for i := 0 to viewsLength - 1 do
  begin
    vView := views[i];
    if vView.viewName = viewName then
      begin
      fView := vView;
      break;
      end
    else
      begin
      subViews := vView.views;
      subViewsLength := High(subViews) - Low(subViews) + 1;
      if subViewsLength > 0 then
        begin
        fView := FindViewByName(viewName, subViews);
        break;
        end;
      end;
  end;
  FindViewByName := fView;
end;

function FindView(mp:FCPoint; var views:viewArray):FCView;
var
  viewsLength:integer;
  i:integer;
  vView:FCView;
  subViews:viewArray;
  subViewsLength:integer;
  clx:double;
  cly:double;
  subView:FCView;
  fView:FCView;
  hasPoint:boolean;
begin
  fView := FCView.Create();
  fView.isNotEmpty := false;
  fView.uid := -1;
  viewsLength := High(views) - Low(views) + 1;
  clx := 0;
  cly := 0;
  for i := 0 to viewsLength - 1 do
  begin
    vView := views[viewsLength - i - 1];
    if vView.visible and vView.topMost then
      begin
      hasPoint := false;
      if OnContainsPointEvent <> nil then
        hasPoint := OnContainsPointEvent(vView, mp)
      else
        hasPoint := ContainsPoint(vView, mp);
      if hasPoint then
        begin
        if vView.vScrollIsVisible and (vView.scrollSize > 0) then
          begin
					clx := ClientX(vView);
					if mp.x >= clx + vView.size.cx - vView.scrollSize then
            begin
						fView := vView;
            break;
            end;
          end;
				if vView.hScrollIsVisible and (vView.scrollSize > 0) then
          begin
					cly := ClientY(vView);
					if mp.y >= cly + vView.size.cy - vView.scrollSize then
						begin
						fView := vView;
            break;
            end;
          end;
				subViews := vView.views;
        subViewsLength := High(subViews) - Low(subViews) + 1;
				if subViewsLength > 0 then
          begin
					subView := FindView(mp, subViews);
					if subView.isNotEmpty then
            begin
						fView := subView;
            break;
            end;
          end;
				fView := vView;
        break;
        end;
      end;
  end;
  if fView.isNotEmpty = false then
  begin
    for i := 0 to viewsLength - 1 do
    begin
      vView := views[viewsLength - i - 1];
      if vView.visible and (vView.topMost = false) then
        begin
        hasPoint := false;
        if OnContainsPointEvent <> nil then
          hasPoint := OnContainsPointEvent(vView, mp)
        else
          hasPoint := ContainsPoint(vView, mp);
        if hasPoint then
          begin
          if vView.vScrollIsVisible and (vView.scrollSize > 0) then
            begin
            clx := ClientX(vView);
            if mp.x >= clx + vView.size.cx - vView.scrollSize then
              begin
              fView := vView;
              break;
              end;
            end;
          if vView.hScrollIsVisible and (vView.scrollSize > 0) then
            begin
            cly := ClientY(vView);
            if mp.y >= cly + vView.size.cy - vView.scrollSize then
              begin
              fView := vView;
              break;
              end;
            end;
          subViews := vView.views;
          subViewsLength := High(subViews) - Low(subViews) + 1;
          if subViewsLength > 0 then
            begin
            subView := FindView(mp, subViews);
            if subView.isNotEmpty then
              begin
              fView := subView;
              break;
              end;
            end;
          fView := vView;
          break;
          end;
        end;
    end;
  end;
  FindView := fView
end;

function IsPaintVisible(var inView:FCView):boolean;
var
  pView:FCView;
begin
  if inView.visible then
    begin
    pView := inView.GetParent();
    if pView.isNotEmpty then
      begin
      if pView.visible then
        IsPaintVisible := IsPaintVisible(pView)
      else
        IsPaintVisible := false;
      end
    else
      IsPaintVisible := true;
    end
  else
    begin
    IsPaintVisible := false;
    end;
end;

function IsViewEnabled(var inView:FCView):boolean;
var
  pView:FCView;
begin
  if inView.visible then
    pView := inView.GetParent();
    if pView.isNotEmpty then
      begin
      if pView.visible then
        IsViewEnabled := IsViewEnabled(pView)
      else
        IsViewEnabled := false;
      end
    else
      IsViewEnabled := true;
end;

function GetIntersectRect(var lpDestRect:FCRect; var lpSrc1Rect:FCRect; var lpSrc2Rect:FCRect) :integer;
begin
  if lpSrc1Rect.left > lpSrc2Rect.left then
    lpDestRect.left := lpSrc1Rect.left
  else
    lpDestRect.left := lpSrc2Rect.left;
  if lpSrc1Rect.right < lpSrc2Rect.right then
    lpDestRect.right := lpSrc1Rect.right
  else
    lpDestRect.right := lpSrc2Rect.right;
  if lpSrc1Rect.top > lpSrc2Rect.top then
    lpDestRect.top := lpSrc1Rect.top
  else
    lpDestRect.top := lpSrc2Rect.top;
  if lpSrc1Rect.bottom < lpSrc2Rect.bottom then
    lpDestRect.bottom := lpSrc1Rect.bottom
  else
    lpDestRect.bottom := lpSrc2Rect.bottom;
  if (lpDestRect.right > lpDestRect.left) and (lpDestRect.bottom > lpDestRect.top) then
    begin
    GetIntersectRect := 1;
    end
  else
    begin
    lpDestRect.left := 0;
    lpDestRect.right := 0;
    lpDestRect.top := 0;
    lpDestRect.bottom := 0;
    GetIntersectRect := 0;
    end;
end;

function GetFormatDate(num:double; formatStr:string):string;
begin
  GetFormatDate := FloatToStr(num);
end;

procedure DrawCheckBox(var checkBox:FCCheckBox; var paint:FCPaint; clipRect:FCRect);
var
  width:double;
  height:double;
  eRight:double;
  eRect:FCRect;
  tSize:FCSize;
  drawPoints:array of FCPoint;
begin
  width := checkBox.size.cx;
  height := checkBox.size.cy;
  if checkBox.textColor <> 'none' then
    begin
    eRight := checkBox.buttonSize.cx + 10;
    eRect := FCRect.Create(1, (height - checkBox.buttonSize.cy) / 2, checkBox.buttonSize.cx + 1, (height + checkBox.buttonSize.cy) / 2);
    if length(checkBox.text) = 0 then
      begin
      eRect := FCRect.Create((width - checkBox.buttonSize.cx) / 2, (height - checkBox.buttonSize.cy) / 2, (width + checkBox.buttonSize.cx) / 2, (height + checkBox.buttonSize.cy) / 2);
      end;
    paint.DrawRect(checkBox.textColor, 1, 0, eRect.left, eRect.top, eRect.right, eRect.bottom);
    if checkBox.checked then
      begin
      SetLength(drawPoints, 3);
      drawPoints[0] := FCPoint.Create(eRect.left + 2, eRect.top + 8 + 2);
      drawPoints[1] := FCPoint.Create(eRect.left + 6 + 2, eRect.bottom - 2);
      drawPoints[2] := FCPoint.Create(eRect.right - 1 - 2, eRect.top + 2);
      paint.DrawPolyline(checkBox.textColor, 1, 0, drawPoints);
      end;
    if length(checkBox.text) > 0 then
      begin
			tSize := paint.TextSize(checkBox.text, checkBox.font);
			paint.DrawText(checkBox.text, checkBox.textColor, checkBox.font, eRight, (height - tSize.cy) / 2);
		  end;
    end;
end;

procedure DrawRadioButton(var radioButton:FCRadioButton; var paint:FCPaint; clipRect:FCRect);
var
  width:double;
  height:double;
  eRight:double;
  eRect:FCRect;
  tSize:FCSize;
begin
  width := radioButton.size.cx;
  height := radioButton.size.cy;
  if radioButton.textColor <> 'none' then
    begin
    eRight := radioButton.buttonSize.cx + 10;
    eRect := FCRect.Create(1, (height - radioButton.buttonSize.cy) / 2, radioButton.buttonSize.cx + 1, (height + radioButton.buttonSize.cy) / 2);
    if length(radioButton.text) = 0 then
      begin
      eRect := FCRect.Create((width - radioButton.buttonSize.cx) / 2, (height - radioButton.buttonSize.cy) / 2, (width + radioButton.buttonSize.cx) / 2, (height + radioButton.buttonSize.cy) / 2);
      end;
    paint.DrawEllipse(radioButton.textColor, 1, 0, eRect.left, eRect.top, eRect.right, eRect.bottom);
    if radioButton.checked then
      begin
      paint.FillEllipse(radioButton.textColor, eRect.left + 2, eRect.top + 2, eRect.right - 2, eRect.bottom - 2);
      end;
    if length(radioButton.text) > 0 then
      begin
			tSize := paint.TextSize(radioButton.text, radioButton.font);
			paint.DrawText(radioButton.text, radioButton.textColor, radioButton.font, eRight, (height - tSize.cy) / 2);
		  end;
    end;
end;

procedure DrawButton(var button:FCView; var paint:FCPaint; clipRect:FCRect);
var
  tSize:FCSize;
begin
  if button.uid = touchDownView.uid then 
    begin
		if button.pushedColor <> 'none' then
			paint.FillRoundRect(button.pushedColor, 0, 0, button.size.cx, button.size.cy, button.cornerRadius)
		else
			if button.backColor <> 'none' then
				paint.FillRoundRect(button.backColor, 0, 0, button.size.cx, button.size.cy, button.cornerRadius);
    end
	else if button.uid = touchMoveView.uid then
    begin
		if button.hoveredColor <> 'none' then
			paint.FillRoundRect(button.hoveredColor, 0, 0, button.size.cx, button.size.cy, button.cornerRadius)
		else
			if button.backColor <> 'none' then
				paint.FillRoundRect(button.backColor, 0, 0, button.size.cx, button.size.cy, button.cornerRadius);
    end
	else if button.backColor <> 'none' then
    begin
		paint.FillRoundRect(button.backColor, 0, 0, button.size.cx, button.size.cy, button.cornerRadius);
    end;
	if (button.textColor <> 'none') and (length(button.text) > 0) then
    begin
		tSize := paint.TextSize(button.text, button.font);
		paint.DrawText(button.text, button.textColor, button.font, (button.size.cx - tSize.cx) / 2, (button.size.cy  - tSize.cy) / 2);
    end;
  if button.borderColor <> 'none' then
		paint.DrawRoundRect(button.borderColor, button.borderWidth, 0, 0, 0, button.size.cx, button.size.cy, button.cornerRadius);
end;

procedure ClickCheckBox(var checkBox:FCCheckBox; mp:FCPoint);
begin
  if checkBox.checked then
    checkBox.checked := false
  else
    checkBox.checked := true;
end;

procedure ClickRadioButton(var radioButton:FCRadioButton; mp:FCPoint);
var
  hasOther:boolean;
  pLength:integer;
  inRadioButton2:FCRadioButton;
  rView:FCView;
  i:integer;
  pView:FCView;
begin
  hasOther := false;
  pLength := 0;
  pView := radioButton.GetParent();
  if pView.isNotEmpty then
  begin
    pLength := High(pView.views) - Low(pView.views) + 1;
    for i := 0 to pLength - 1 do
    begin
      rView := pView.views[i];
      if rView.viewType = 'radiobutton' then
        begin
        if (rView.uid <> radioButton.uid) and (FCRadioButton(rView).groupName = radioButton.groupName) then
          begin
          inRadioButton2 := FCRadioButton(rView);
          inRadioButton2.checked := false;
          end;
        end;
    end;
  end;
	radioButton.checked := true;
end;

function GetDaysInMonth(year:integer; month:integer):integer;
var
  daysInMonth:integer;
begin
  if (month = 1) or (month = 3) or (month = 5) or (month = 7) or (month = 8) or (month = 10) or (month = 12) then
		daysInMonth := 31
	else if (month = 4) or (month = 6) or (month = 9) or (month = 11) then
		daysInMonth := 30
	else
    begin
		if ((year mod 4 = 0) and (year mod 100 <> 0)) or (year mod 400 = 0) then
				daysInMonth := 29
		else
			daysInMonth := 28;
    end;
  GetDaysInMonth := daysInMonth;
end;

function GetMonthStr(month:integer):string;
var
  monthStr:string;
begin
  if month = 1 then
		monthStr := '一月'
	else if month = 2 then
		monthStr := '二月'
	else if month = 3 then
		monthStr := '三月'
	else if month = 4 then
		monthStr := '四月'
	else if month = 5 then
		monthStr := '五月'
	else if month = 6 then
		monthStr := '六月'
	else if month = 7 then
		monthStr := '七月'
	else if month = 8 then
		monthStr := '八月'
	else if month = 9 then
		monthStr := '九月'
	else if month = 10 then
		monthStr := '十月'
	else if month = 11 then
		monthStr := '十一月'
	else if month = 12 then
		monthStr := '十二月';
  GetMonthStr := monthStr;
end;

function GetYear(var calendar:FCCalendar; year:integer):CYear;
var
  yearLength:integer;
  cy:CYear;
  find:boolean;
  i:integer;
  iYear:CYear;
  iMonth:CMonth;
  iDay:CDay;
  daysInMonth:integer;
  j:integer;
  k:integer;
begin
  find := false;
  yearLength := High(calendar.years) - Low(calendar.years) + 1;
  for k := 0 to yearLength - 1 do
  begin
    iYear := calendar.years[k];
    cy := iYear;
    find := true;
  end;
  if find = false then
  begin
    cy := CYear.Create();
    SetLength(calendar.years, yearLength + 1);
    calendar.years[yearLength] := cy;
    cy.year := year;
    SetLength(cy.months, 13);
    for i := 0 to 12 do
    begin
      iMonth := CMonth.Create();
      iMonth.year := year;
			iMonth.month := i;
      daysInMonth := GetDaysInMonth(year, i);
      SetLength(iMonth.days, daysInMonth + 1);
      for j := 0 to daysInMonth do
      begin
        iDay := CDay.Create();
				iDay.year := year;
				iDay.month := i;
				iDay.day := j;
				iMonth.days[j] := iDay;
      end;
      cy.months[i] := iMonth;
    end;
  end;
  GetYear := cy;
end;

procedure ShowOrHideDayDiv(var dDiv:DayDiv; visible:boolean);
var
  dayButtonsSize:integer;
  i:integer;
begin
  dayButtonsSize := High(dDiv.dayButtons) - Low(dDiv.dayButtons) + 1;
  for i := 0 to dayButtonsSize - 1 do
  begin
    dDiv.dayButtons[i].visible := visible;
  end;
end;

procedure ShowOrHideMonthDiv(var mDiv:MonthDiv; visible:boolean);
var
  monthButtonsSize:integer;
  i:integer;
begin
  monthButtonsSize := High(mDiv.monthButtons) - Low(mDiv.monthButtons) + 1;
  for i := 0 to monthButtonsSize - 1 do
  begin
    mDiv.monthButtons[i].visible := visible;
  end;
end;

procedure showOrHideYearDiv(var yDiv:YearDiv; visible:boolean);
var
  yearButtonsSize:integer;
  i:integer;
begin
  yearButtonsSize := High(yDiv.yearButtons) - Low(yDiv.yearButtons) + 1;
  for i := 0 to yearButtonsSize - 1 do
  begin
    yDiv.yearButtons[i].visible := visible;
  end;
end;

procedure InitCalendar(var calendar:FCCalendar);
var
  i:integer;
  dButton:DayButton;
  dButtonAm:DayButton;
  mButton:MonthButton;
  mButtonAm:MonthButton;
  yButton:YearButton;
  yButtonAm:YearButton;
  dDiv:DayDiv;
  mDiv:MonthDiv;
  yDiv:YearDiv;
begin
  dDiv := calendar.dDiv;
  mDiv := calendar.mDiv;
  yDiv := calendar.yDiv;
  for i := 0 to 41 do
  begin
		dButton := DayButton.Create();
		dDiv.dayButtons[i] := dButton;
		dButtonAm := DayButton.Create();
		dButtonAm.visible := false;
    dDiv.dayButtons_am[i] := dButtonAm;
  end;
	for i := 0 to 11 do
  begin
		mButton := MonthButton.Create();
		mButton.month := (i + 1);
		mDiv.monthButtons[i] := mButton;
		mButtonAm := MonthButton.Create();
		mButtonAm.visible := false;
		mButtonAm.month := (i + 1);
		mDiv.monthButtons_am[i] := mButtonAm;
  end;
	for i := 0 to 11 do
  begin
		yButton := YearButton.Create();
		yDiv.yearButtons[i] := yButton;
		yButtonAm := YearButton.Create();
		yButtonAm.visible := false;
		yDiv.yearButtons_am[i] := yButtonAm;
  end;
end;

function DayOfWeek(y:integer; m:integer; d:integer):integer;
begin
  if (m = 1) or (m = 2) then
    begin
		m := m + 12;
		y := y - 1;
    end;
	DayOfWeek := trunc(((d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) + 1) mod 7);
end;

function GetMonth(var calendar:FCCalendar):CMonth;
begin
  GetMonth := GetYear(calendar, calendar.selectedDay.year).months[calendar.selectedDay.month];
end;

function GetNextMonth(var calendar:FCCalendar; year:integer; month:integer):CMonth;
var
  nextMonth:integer;
  nextYear:integer;
begin
  nextMonth := month + 1;
	nextYear := year;
	if nextMonth = 13 then
    begin
		nextMonth := 1;
		nextYear := nextYear + 1;
    end;
	GetNextMonth := GetYear(calendar, nextYear).months[nextMonth];
end;

function GetLastMonth(var calendar:FCCalendar; year:integer; month:integer):CMonth;
var
  nextMonth:integer;
  nextYear:integer;
begin
  nextMonth := month - 1;
	nextYear := year;
	if nextMonth = 0 then
    begin
		nextMonth := 12;
		nextYear := nextYear - 1;
    end;
	GetLastMonth := GetYear(calendar, nextYear).months[nextMonth];
end;

procedure ResetDayDiv(var calendar:FCCalendar; var dDiv:DayDiv; state:integer);
var
  vDayButton:DayButton;
  thisMonth:CMonth;
  lastMonth:CMonth;
  nextMonth:CMonth;
  left:double;
  headHeight:double;
  top:double;
  width:double;
  height:double;
  dayButtonHeight:double;
  toY:double;
  month:integer;
  buttonSize:integer;
  dheight:double;
  days:array of CDay;
  firstDay:CDay;
  startDayOfWeek:integer;
  i:integer;
  vOffset:double;
  dp:FCPoint;
  ds:FCSize;
  bounds:FCRect;
  daysLength:integer;
  lastMonthDaysLength:integer;
  vDay:CDay;
begin
  thisMonth := GetMonth(calendar);
	lastMonth := GetLastMonth(calendar, thisMonth.year, thisMonth.month);
	nextMonth := GetNextMonth(calendar, thisMonth.year, thisMonth.month);
	left := 0;
	headHeight := calendar.hDiv.bounds.bottom;
	top := headHeight;
	width := calendar.size.cx;
	height := calendar.size.cy;
	height := height - calendar.tDiv.bounds.bottom - calendar.tDiv.bounds.top;
	dayButtonHeight := height - headHeight;
	if dayButtonHeight < 1 then
    begin
		dayButtonHeight := 1;
    end;
	toY := 0;
  if dDiv.aDirection = 1 then
    begin
		toY := dayButtonHeight * dDiv.aTick / dDiv.aTotalTick;
		if state = 1 then
      begin
			thisMonth := nextMonth;
			month := thisMonth.month;
			lastMonth := GetLastMonth(calendar, thisMonth.year, month);
			nextMonth := GetNextMonth(calendar, thisMonth.year, month);
      end;
    end
	else if dDiv.aDirection = 2 then
    begin
		toY := -dayButtonHeight * dDiv.aTick / dDiv.aTotalTick;
		if state = 1 then
      begin
			thisMonth := lastMonth;
			month := thisMonth.month;
			lastMonth := GetLastMonth(calendar, thisMonth.year, month);
			nextMonth := GetNextMonth(calendar, thisMonth.year, month);
      end;
    end;
  buttonSize := 0;
	if state = 0 then
		buttonSize := High(dDiv.dayButtons) - Low(dDiv.dayButtons) + 1
	else if state = 1 then
    begin
		buttonSize := High(dDiv.dayButtons_am) - Low(dDiv.dayButtons_am) + 1;
    end;
	dheight := dayButtonHeight / 6;
	days := thisMonth.days;
	firstDay := days[1];
	startDayOfWeek := DayOfWeek(firstDay.year, firstDay.month, firstDay.day);
  for i := 0 to buttonSize - 1 do
  begin
    if state = 0 then
      begin
			vDayButton := dDiv.dayButtons[i];
			buttonSize := High(dDiv.dayButtons) - Low(dDiv.dayButtons) + 1;
      end
		else if state = 1 then
      begin
			vDayButton := dDiv.dayButtons_am[i];
			buttonSize := High(dDiv.dayButtons_am) - Low(dDiv.dayButtons_am) + 1;
      end;
    if i = 35 then
			dheight := height - top;
    vOffset := 0;
		if state = 1 then
      begin
			if dDiv.aTick > 0 then
        begin
				vDayButton.visible := true;
				if dDiv.aDirection = 1 then
					vOffset := toY - dayButtonHeight
				else if dDiv.aDirection = 2 then
					vOffset := toY + dayButtonHeight;
        end
			else
				vDayButton.visible := false;
				continue;
      end
		else
      begin
			vOffset := toY;
      end;
    if (i + 1) mod 7 = 0 then
      begin
			dp := FCPoint.Create(left, top + vOffset);
			ds := FCSize.Create(width - left, dheight);
			bounds := FCRect.Create(dp.x, dp.y, dp.x + ds.cx, dp.y + ds.cy);
			vDayButton.bounds := bounds;
			left := 0;
			if (i <> 0) and (i <> buttonSize - 1) then
				top := top + dheight;
      end
		else
      begin
			dp := FCPoint.Create(left, top + vOffset);
			ds := FCSize.Create(width / 7 + ((i + 1) mod 7) mod 2, dheight);
			bounds := FCRect.Create(dp.x, dp.y, dp.x + ds.cx, dp.y + ds.cy);
			vDayButton.bounds := bounds;
			left := left + ds.cx;
      end;
    vDayButton.inThisMonth := false;
    daysLength := High(days) - Low(days);
    lastMonthDaysLength := High(lastMonth.days) - Low(lastMonth.days);
		if (i >= startDayOfWeek) and (i <= startDayOfWeek + daysLength - 1) then
      begin
			vDay := days[i - startDayOfWeek + 1];
			vDayButton.inThisMonth := true;
      end
		else if i < startDayOfWeek then
      begin
			vDay := lastMonth.days[lastMonthDaysLength - startDayOfWeek + i + 1];
      end
		else if i > startDayOfWeek + daysLength - 1 then
      begin
			vDay := nextMonth.days[i - startDayOfWeek - daysLength + 1];
      end;
		vDayButton.day := vDay;
	  //if (state = 0) and vDayButton.day.isNotEmpty and (vDayButton.day = calendar.selectedDay) then
			//vDayButton.selected := true;
		//else
			//vDayButton.selected := false;
  end;
end;

procedure ResetMonthDiv(var calendar:FCCalendar; var mDiv:MonthDiv; state:integer);
var
  thisYear:integer;
	lastYear:integer;
	nextYear:integer;
	left:double;
	headHeight:double;
	top:double;
	width:double;
	height:double;
	monthButtonHeight:double;
  toY:double;
  dheight:double;
  buttonSize:integer;
  vOffSet:double;
  dp:FCPoint;
  ds:FCSize;
  bounds:FCRect;
  i:integer;
  monthButtons:array of MonthButton;
  vMonthButton:MonthButton;
begin
  thisYear := mDiv.year;
	lastYear := mDiv.year - 1;
	nextYear := mDiv.year + 1;
	left := 0;
	headHeight := calendar.hDiv.bounds.bottom;
	top := headHeight;
	width := calendar.size.cx;
	height := calendar.size.cy;
	height := height - calendar.tDiv.bounds.bottom - calendar.tDiv.bounds.top;
	monthButtonHeight := height - top;
	if monthButtonHeight < 1 then
    begin
		monthButtonHeight := 1;
    end;
	toY := 0;
  if mDiv.aDirection = 1 then
    begin
		toY := monthButtonHeight * mDiv.aTick / mDiv.aTotalTick;
		if state = 1 then
      begin
			thisYear := nextYear;
			lastYear := thisYear - 1;
			nextYear := thisYear + 1;
      end;
    end
	else if mDiv.aDirection = 2 then
		toY := -monthButtonHeight * mDiv.aTick / mDiv.aTotalTick;
		if state = 1 then
      begin
			thisYear := lastYear;
			lastYear := thisYear - 1;
			nextYear := thisYear + 1;
      end;
	if state = 0 then
		monthButtons := mDiv.monthButtons
	else if state = 1 then
    begin
		monthButtons := mDiv.monthButtons_am;
    end;
	dheight := monthButtonHeight / 3;
	buttonSize := High(monthButtons) - Low(monthButtons) + 1;
  for i := 0 to buttonSize - 1 do
  begin
    if i = 8 then
      begin
			dheight := height - top;
      end;
    vMonthButton := monthButtons[i];
		vMonthButton.year := thisYear;
		vOffSet := 0;
    if state = 1 then
      begin
			if mDiv.aTick > 0 then
        begin
				vMonthButton.visible := true;
				if mDiv.aDirection = 1 then
					vOffSet := toY - monthButtonHeight
				else if mDiv.aDirection = 2 then
					vOffSet := toY + monthButtonHeight;
        end
			else
				vMonthButton.visible := false;
				continue;
      end
		else
			vOffSet := toY;
    if (i + 1) mod 4 = 0 then
      begin
			dp := FCPoint.Create(left, top + vOffSet);
			ds := FCSize.Create(width - left, dheight);
			bounds := FCRect.Create(dp.x, dp.y, dp.x + ds.cx, dp.y + ds.cy);
			vMonthButton.bounds := bounds;
			left := 0;
			if (i <> 0) and (i <> buttonSize - 1) then
				top := top + dheight;
      end
		else
      begin
			dp := FCPoint.Create(left, top + vOffSet);
			ds := FCSize.Create( width / 4 + ((i + 1) mod 4) mod 2, dheight);
			bounds := FCRect.Create(dp.x, dp.y, dp.x + ds.cx, dp.y + ds.cy);
			vMonthButton.bounds := bounds;
			left := left + ds.cx;
      end;
  end;
end;

procedure ResetYearDiv(var calendar:FCCalendar; var yDiv:YearDiv; state:integer);
var
  thisStartYear:integer;
	lastStartYear:integer;
	nextStartYear:integer;
	left:double;
	headHeight:double;
	top:double;
	width:double;
	height:double;
	yearButtonHeight :double;
	toY:double;
  yearButtons:array of YearButton;
  vYearButton:YearButton;
  vOffSet:double;
  dp:FCPoint;
  ds:FCSize;
  bounds:FCRect;
  i:integer;
  dheight:double;
  buttonSize:integer;
begin
  thisStartYear := yDiv.startYear;
	lastStartYear := yDiv.startYear - 12;
	nextStartYear := yDiv.startYear + 12;
	left := 0;
	headHeight := calendar.hDiv.bounds.bottom;
	top := headHeight;
	width := calendar.size.cx;
	height := calendar.size.cy;
	height := height - calendar.tDiv.bounds.bottom - calendar.tDiv.bounds.top;
	yearButtonHeight := height - top;
	if yearButtonHeight < 1 then
    begin
		yearButtonHeight := 1;
    end;
	toY := 0;
  if yDiv.aDirection = 1 then
    begin
		toY := yearButtonHeight * yDiv.aTick / yDiv.aTotalTick;
		if state = 1 then
      begin
			thisStartYear := nextStartYear;
			lastStartYear := thisStartYear - 12;
			nextStartYear := thisStartYear + 12;
      end;
		end
	else if yDiv.aDirection = 2 then
		toY := -yearButtonHeight * yDiv.aTick / yDiv.aTotalTick;
		if state = 1 then
      begin
			thisStartYear := lastStartYear;
			lastStartYear := thisStartYear - 12;
			nextStartYear := thisStartYear + 12;
      end;
  if state = 0 then
		yearButtons := yDiv.yearButtons
	else if state = 1 then
		yearButtons := yDiv.yearButtons_am;
	dheight := yearButtonHeight / 3;
	buttonSize := High(yDiv.yearButtons) - Low(yDiv.yearButtons_am) + 1;
  for i := 0 to buttonSize - 1 do
  begin
    if i = 8 then
      begin
			dheight := height - top;
      end;
    vYearButton := yearButtons[i];
    vYearButton.year := thisStartYear + i;
		vOffSet := 0;
		if state = 1 then
      begin
			if yDiv.aTick > 0 then
        begin
				vYearButton.visible := true;
				if yDiv.aDirection = 1 then
					vOffSet := toY - yearButtonHeight
				else if yDiv.aDirection = 2 then
					vOffSet := toY + yearButtonHeight;
        end
			else
				vYearButton.visible := false;
				continue;
      end
		else
			vOffSet := toY;
    if (i + 1) mod 4 = 0 then
      begin
			dp := FCPoint.Create(left, top + vOffSet);
			ds := FCSize.Create(width - left, dheight);
			bounds := FCRect.Create(dp.x, dp.y, dp.x + ds.cx, dp.y + ds.cy);
			vYearButton.bounds := bounds;
			left := 0;
			if (i <> 0) and (i <> buttonSize - 1) then
				top := top + dheight;
      end
		else
      begin
			dp := FCPoint.Create(left, top + vOffSet);
			ds := FCSize.Create(width / 4 + ((i + 1) mod 4) mod 2, dheight);
			bounds := FCRect.Create(dp.x, dp.y, dp.x + ds.cx, dp.y + ds.cy);
			vYearButton.bounds := bounds;
			left := left + ds.cx;
      end;
  end;
end;

procedure SelectStartYear(var calendar:FCCalendar; var yDiv:YearDiv; startYear:integer);
begin
  if yDiv.startYear <> startYear then
		if startYear > yDiv.startYear then
			yDiv.aDirection := 1
		else
      begin
			yDiv.aDirection := 2;
      end;
		if calendar.useAnimation then
      begin
			yDiv.aTick := yDiv.aTotalTick;
      end;
		yDiv.startYear := startYear;
end;

procedure SelectYear(var calendar:FCCalendar; var mDiv:MonthDiv; year:integer);
begin
  if mDiv.year <> year then
		if year > mDiv.year then
			mDiv.aDirection := 1
		else
      begin
			mDiv.aDirection := 2;
      end;
		if calendar.useAnimation then
      begin
			mDiv.aTick := mDiv.aTotalTick;
      end;
		mDiv.year := year;
end;

procedure UpdateCalendar(var calendar:FCCalendar);
begin
  calendar.hDiv.bounds := FCRect.Create(0, 0, calendar.size.cx, 80);
	if calendar.mode = 'day' then
    begin
		ResetDayDiv(calendar, calendar.dDiv, 0);
		ResetDayDiv(calendar, calendar.dDiv, 1);
    end
	else if calendar.mode = 'month' then
    begin
		ResetMonthDiv(calendar, calendar.mDiv, 0);
		ResetMonthDiv(calendar, calendar.mDiv, 1);
    end
	else if calendar.mode = 'year' then
    begin
		ResetYearDiv(calendar, calendar.yDiv, 0);
		ResetYearDiv(calendar, calendar.yDiv, 1);
    end;
end;

procedure DrawHeadDiv(var calendar:FCCalendar; var hDiv:HeadDiv; var paint:FCPaint);
var
  bounds:FCRect;
  weekStrings:array of string;
  w:double;
  left:double;
  i:integer;
  weekDaySize:FCSize;
  textX:double;
  textY:double;
  drawTitle:string;
  tR:double;
  tSize:FCSize;
  drawPoints:array of FCPoint;
begin
  bounds := hDiv.bounds;
	if hDiv.backColor <> 'none' then
    begin
		paint.FillRect(hDiv.backColor, bounds.left, bounds.top, bounds.right, bounds.bottom);
    end;
  SetLength(weekStrings, 7);
  weekStrings[0] := '周日';
	weekStrings[1] := '周一';
	weekStrings[2] := '周二';
	weekStrings[3] := '周三';
	weekStrings[4] := '周四';
	weekStrings[5] := '周五';
	weekStrings[6] := '周六';
  w := bounds.right - bounds.left;
	left := bounds.left;
  for i := 0 to 6 do
  begin
    weekDaySize := paint.TextSize(weekStrings[i], hDiv.weekFont);
		textX := left + (w / 7) / 2 - weekDaySize.cx / 2;
		textY := bounds.bottom - weekDaySize.cy - 2;
		paint.DrawText(weekStrings[i], hDiv.textColor, hDiv.weekFont, textX, textY);
		left := left + w / 7;
  end;
  drawTitle := '';
  if calendar.mode = 'day' then
		drawTitle := IntToStr(calendar.selectedDay.year) + '年' + IntToStr(calendar.selectedDay.month) + '月'
	else if calendar.mode = 'month' then
		drawTitle := IntToStr(calendar.mDiv.year) + '年'
	else
		drawTitle := IntToStr(calendar.yDiv.startYear) + '年-' + IntToStr(calendar.yDiv.startYear + 11) + '年';
  tSize := paint.TextSize(drawTitle, hDiv.titleFont);
	paint.DrawText(drawTitle, hDiv.textColor, hDiv.titleFont, bounds.left + (w - tSize.cx) / 2, 30);
	tR := 10;
  SetLength(drawPoints, 3);
  drawPoints[0] := FCPoint.Create(5, bounds.top + (bounds.bottom - bounds.top) / 2);
	drawPoints[1] := FCPoint.Create(5 + tR * 2, bounds.top + (bounds.bottom - bounds.top) / 2 - tR);
	drawPoints[2] := FCPoint.Create(5 + tR * 2, bounds.top + (bounds.bottom - bounds.top) / 2 + tR);
	paint.FillPolygon(hDiv.arrowColor, drawPoints);
	drawPoints[0] := FCPoint.Create(bounds.right - 5, bounds.top + (bounds.bottom - bounds.top) / 2);
	drawPoints[1] := FCPoint.Create(bounds.right - 5 - tR * 2, bounds.top + (bounds.bottom - bounds.top) / 2 - tR);
	drawPoints[2] := FCPoint.Create(bounds.right - 5 - tR * 2, bounds.top + (bounds.bottom - bounds.top) / 2 + tR);
	paint.FillPolygon(hDiv.arrowColor, drawPoints);
end;

procedure DrawDayButton(var calendar:FCCalendar; var dButton:DayButton; var paint:FCPaint);
var
  bounds:FCRect;
  text:string;
  tSize:FCSize;
begin
  if dButton.day.isNotEmpty then
    begin
		bounds := dButton.bounds;
		text := IntToStr(dButton.day.day); 
		tSize := paint.TextSize(text, dButton.font);
		if dButton.backColor <> 'none' then
      begin
			paint.FillRect(dButton.backColor, bounds.left + 2, bounds.top + 2, bounds.right - 2, bounds.bottom - 2);
      end;
		if dButton.inThisMonth then
			paint.DrawText(text, dButton.textColor, dButton.font, bounds.left + 5, bounds.top + 7)
		else
      begin
			paint.DrawText(text, dButton.textColor2, dButton.font, bounds.left + 5, bounds.top + 7);
      end;
		if dButton.borderColor <> 'none' then
			paint.DrawRect(dButton.borderColor, 1, 0, bounds.left + 2, bounds.top + 2, bounds.right - 2, bounds.bottom - 2);
    end;
end;

procedure DrawMonthButton(var calendar:FCCalendar; var mButton:MonthButton; var paint:FCPaint);
var
  bounds:FCRect;
  text:string;
  tSize:FCSize;
begin
  bounds := mButton.bounds;
  text := GetMonthStr(mButton.month);
  tSize := paint.TextSize(text, mButton.font);
  if mButton.backColor <> 'none' then
    begin
    paint.FillRect(mButton.backColor, bounds.left + 2, bounds.top + 2, bounds.right - 2, bounds.bottom - 2);
    end;
  paint.DrawText(text, mButton.textColor, mButton.font, bounds.left + 5, bounds.top + 7);
  if mButton.borderColor <> 'none' then
    paint.DrawRect(mButton.borderColor, 1, 0, bounds.left + 2, bounds.top + 2, bounds.right - 2, bounds.bottom - 2);
end;

procedure DrawYearButton(var calendar:FCCalendar; var yButton:YearButton; var paint:FCPaint);
var
  bounds:FCRect;
  text:string;
  tSize:FCSize;
begin
  bounds := yButton.bounds;
  text := IntToStr(yButton.year);
  tSize := paint.TextSize(text, yButton.font);
  if yButton.backColor <> 'none' then
    begin
    paint.FillRect(yButton.backColor, bounds.left + 2, bounds.top + 2, bounds.right - 2, bounds.bottom - 2);
    end;
  paint.DrawText(text, yButton.textColor, yButton.font, bounds.left + 5, bounds.top + 7);
  if yButton.borderColor <> 'none' then
    paint.DrawRect(yButton.borderColor, 1, 0, bounds.left + 2, bounds.top + 2, bounds.right - 2, bounds.bottom - 2);
end;

procedure DrawCalendar(var calendar:FCCalendar; var paint:FCPaint);
var
  dayButtonsSize:integer;
  monthButtonsSize:integer;
  yearButtonsSize:integer;
  i:integer;
  vDayButton:DayButton;
  vMonthButton:MonthButton;
  vYearButton:YearButton;
begin
  if calendar.backColor <> 'none' then
    begin
		paint.FillRect(calendar.backColor, 0, 0, calendar.size.cx, calendar.size.cy);
    end;
  if calendar.mode = 'day' then
    begin
    dayButtonsSize := High(calendar.dDiv.dayButtons) - Low(calendar.dDiv.dayButtons) + 1;
    for i := 0 to dayButtonsSize - 1 do
    begin
      vDayButton := calendar.dDiv.dayButtons[i];
      if vDayButton.visible then
        DrawDayButton(calendar, vDayButton, paint);
    end;
    dayButtonsSize := High(calendar.dDiv.dayButtons_am) - Low(calendar.dDiv.dayButtons_am) + 1;
    for i := 0 to dayButtonsSize - 1 do
    begin
      vDayButton := calendar.dDiv.dayButtons_am[i];
      if vDayButton.visible then
        DrawDayButton(calendar, vDayButton, paint);
    end;
    end
  else if calendar.mode = 'month' then
    begin
    monthButtonsSize := High(calendar.mDiv.monthButtons) - Low(calendar.mDiv.monthButtons) + 1;
    for i := 0 to monthButtonsSize - 1 do
    begin
      vMonthButton := calendar.mDiv.monthButtons[i];
      if vMonthButton.visible then
        DrawMonthButton(calendar, vMonthButton, paint);
    end;
    monthButtonsSize := High(calendar.mDiv.monthButtons_am) - Low(calendar.mDiv.monthButtons_am) + 1;
    for i := 0 to monthButtonsSize - 1 do
    begin
      vMonthButton := calendar.mDiv.monthButtons_am[i];
      if vMonthButton.visible then
        DrawMonthButton(calendar, vMonthButton, paint);
    end;
    end
  else if calendar.mode = 'year' then
    yearButtonsSize := High(calendar.yDiv.yearButtons) - Low(calendar.yDiv.yearButtons) + 1;
    for i := 0 to yearButtonsSize - 1 do
    begin
      vYearButton := calendar.yDiv.yearButtons[i];
      if vYearButton.visible then
        DrawYearButton(calendar, vYearButton, paint);
    end;
    yearButtonsSize := High(calendar.yDiv.yearButtons_am) - Low(calendar.yDiv.yearButtons_am) + 1;
    for i := 0 to yearButtonsSize - 1 do
    begin
      vYearButton := calendar.yDiv.yearButtons_am[i];
      if vYearButton.visible then
        DrawYearButton(calendar, vYearButton, paint);
    end;
  DrawHeadDiv(calendar, calendar.hDiv, paint);
  if calendar.borderColor <> 'none' then
		paint.DrawRect(calendar.borderColor, 1, 0, 0, 0, calendar.size.cx, calendar.size.cy);
end;

function GetDivContentWidth(var divView:FCView):double;
var
  cWidth:double;
  i:integer;
  length:integer;
begin
  cWidth := 0;
  length := High(divView.views) - Low(divView.views) + 1;
  if length > 0 then
    for i := 0 to length - 1 do
    begin
      if divView.views[i].visible then
        if cWidth < divView.views[i].location.x + divView.views[i].size.cx then
            cWidth := divView.views[i].location.X + divView.views[i].size.cx;
    end;
  GetDivContentWidth := cWidth;
end;

function GetDivContentHeight(var divView:FCView):double;
var
  cHeight:double;
  i:integer;
  length:integer;
begin
  cHeight := 0;
  length := High(divView.views) - Low(divView.views) + 1;
  if length > 0 then
    for i := 0 to length - 1 do
    begin
      if divView.views[i].visible then
        if cHeight < divView.views[i].location.y + divView.views[i].size.cy then
            cHeight := divView.views[i].location.y + divView.views[i].size.cy;
    end;
  GetDivContentHeight := cHeight;
end;

procedure DrawDivScrollBar(var divView:FCView; var paint:FCPaint; clipRect:FCRect);
var
  contentWidth:double;
  contentHeight:double;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
begin
  divView.hScrollIsVisible := false;
  divView.vScrollIsVisible := false;
  if divView.showHScrollBar then
    begin
		contentWidth := GetDivContentWidth(divView);
		if (contentWidth > 0) and (contentWidth > divView.size.cx) then
      begin
			sLeft := divView.size.cx * divView.scrollH / contentWidth;
			sRight := divView.size.cx * (divView.scrollH + divView.size.cx) / contentWidth;
			if sRight - sLeft < divView.scrollSize then
        begin
				sRight := sLeft + divView.scrollSize;
        end;
			if (touchMoveView.uid = divView.uid) and (divView.hoverScrollHButton or divView.downScrollHButton) then
				paint.FillRect(divView.scrollBarHoveredColor, sLeft, divView.size.cy - divView.scrollSize, sRight, divView.size.cy)
			else
				paint.FillRect(divView.scrollBarColor, sLeft, divView.size.cy - divView.scrollSize, sRight, divView.size.cy);
      divView.hScrollIsVisible := true;
      end;
    end;
	if divView.showVScrollBar then
    begin
		contentHeight := GetDivContentHeight(divView);
		if (contentHeight > 0) and (contentHeight > divView.size.cy) then
      begin
			sTop := divView.scrollV * divView.size.cy / contentHeight;
			sBottom := sTop + (divView.size.cy * divView.size.cy / contentHeight);
			if sBottom - sTop < divView.scrollSize then
        begin
				sBottom := sTop + divView.scrollSize;
        end;
			if (touchMoveView.uid = divView.uid) and (divView.hoverScrollVButton or divView.downScrollVButton) then
				paint.FillRect(divView.scrollBarHoveredColor, divView.size.cx - divView.scrollSize, sTop, divView.size.cx, sBottom)
			else
				paint.FillRect(divView.scrollBarColor, divView.size.cx - divView.scrollSize, sTop, divView.size.cx, sBottom);
      divView.vScrollIsVisible := true;
      end;
    end;
end;

procedure TouchMoveDiv(var divView:FCView; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint);
var
  mp:FCPoint;
  contentWidth:double;
  contentHeight:double;
  subX:double;
  newScrollH:double;
  subY:double;
  newScrollV:double;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
begin
  divView.hoverScrollHButton := false;
	divView.hoverScrollVButton := false;
  mp := firstPoint;
  if firstTouch then
    begin
		if divView.showHScrollBar or divView.showVScrollBar then
      begin
			if divView.downScrollHButton then
        begin
				contentWidth := GetDivContentWidth(divView);
				subX := contentWidth * (mp.x - divView.startPoint.x) / divView.size.cx;
				newScrollH := divView.startScrollH + subX;
				if newScrollH < 0 then
					newScrollH := 0
				else if newScrollH > contentWidth - divView.size.cx then
          begin
					newScrollH := contentWidth - divView.size.cx;
          end;
				divView.scrollH := newScrollH;
				divView.GetPaint().cancelClick := true;
        end
			else if divView.downScrollVButton then
        begin
				contentHeight := GetDivContentHeight(divView);
				subY := contentHeight * (mp.y - divView.startPoint.y) / divView.size.cy;
				newScrollV := divView.startScrollV + subY;
				if newScrollV < 0 then
					newScrollV := 0
				else if newScrollV > contentHeight - divView.size.cy then
          begin
					newScrollV := contentHeight - divView.size.cy;
          end;
				divView.scrollV := newScrollV;
			  divView.GetPaint().cancelClick := true;
        end;
      end;
		if divView.allowDragScroll then
      begin
			contentWidth := GetDivContentWidth(divView);
			if contentWidth > divView.size.cx then
        begin
				subX := divView.startPoint.x - mp.x;
				newScrollH := divView.startScrollH + subX;
				if newScrollH < 0 then
					newScrollH := 0
				else if newScrollH > contentWidth - divView.size.cx then
          begin
					newScrollH := contentWidth - divView.size.cx;
          end;
				divView.scrollH := newScrollH;
				if Abs(subX) > 5 then
					divView.GetPaint().cancelClick := true;
        end;
			contentHeight := GetDivContentHeight(divView);
			if contentHeight > divView.size.cy then
        begin
				subY := divView.startPoint.y - mp.y;
				newScrollV := divView.startScrollV + subY;
				if newScrollV < 0 then
					newScrollV := 0
				else if newScrollV > contentHeight - divView.size.cy then
          begin
					newScrollV := contentHeight - divView.size.cy;
          end;
				divView.scrollV := newScrollV;
				if Abs(subY) > 5 then
					divView.GetPaint().cancelClick := true;
        end;
      end;
    end
	else
		if divView.showHScrollBar then
      begin
			contentWidth := GetDivContentWidth(divView);
			if (contentWidth > 0) and (contentWidth > divView.size.cx) then
        begin
				sLeft := divView.size.cx * divView.scrollH / contentWidth;
				sRight := divView.size.cx * (divView.scrollH + divView.size.cx) / contentWidth;
				if sRight - sLeft < divView.scrollSize then
          begin
					sRight := sLeft + divView.scrollSize;
          end;
				if (mp.x >= sLeft) and (mp.x <= sRight) and (mp.y >= divView.size.cy - divView.scrollSize) and (mp.y <= divView.size.cy) then
					divView.hoverScrollHButton := true
				else
					divView.hoverScrollHButton := false;
        end;
      end;
		if divView.showVScrollBar then
      begin
			contentHeight := GetDivContentHeight(divView);
			if (contentHeight > 0) and (contentHeight > divView.size.cy) then
        begin
				sTop := divView.size.cy * divView.scrollV / contentHeight;
				sBottom := divView.size.cy * (divView.scrollV + divView.size.cy) / contentHeight;
				if sBottom - sTop < divView.scrollSize then
          begin
					sBottom := sTop + divView.scrollSize;
          end;
				if (mp.x >= divView.size.cx - divView.scrollSize) and (mp.x <= divView.size.cx) and (mp.y >= sTop) and (mp.y <= sBottom) then
					divView.hoverScrollVButton := true
				else
					divView.hoverScrollVButton := false;
        end;
      end;
end;

procedure TouchDownDiv(var divView:FCView; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
var
  mp:FCPoint;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
  contentWidth:double;
  contentHeight:double;
begin
  divView.downScrollHButton := false;
	divView.downScrollVButton := false;
	divView.hoverScrollHButton := false;
	divView.hoverScrollVButton := false;
  mp := firstPoint;
  if divView.showHScrollBar then
    begin
		contentWidth := GetDivContentWidth(divView);
		if (contentWidth > 0) and (contentWidth > divView.size.cx) then
      begin
			sLeft := divView.size.cx * divView.scrollH / contentWidth;
			sRight := divView.size.cx * (divView.scrollH + divView.size.cx) / contentWidth;
			if sRight - sLeft < divView.scrollSize then
        begin
				sRight := sLeft + divView.scrollSize;
        end;
			if (mp.x >= sLeft) and (mp.x <= sRight) and (mp.y >= divView.size.cy - divView.scrollSize) and (mp.y <= divView.size.cy) then
        begin
				divView.downScrollHButton := true;
				divView.startScrollH := divView.scrollH;
        end;
      end;
    end;
	if divView.showVScrollBar then
    begin
		contentHeight := GetDivContentHeight(divView);
		if (contentHeight > 0) and (contentHeight > divView.size.cy) then
      begin
			sTop := divView.size.cy * divView.scrollV / contentHeight;
			sBottom := divView.size.cy * (divView.scrollV + divView.size.cy) / contentHeight;
			if sBottom - sTop < divView.scrollSize then
        begin
				sBottom := sTop + divView.scrollSize;
        end;
			if (mp.x >= divView.size.cx - divView.scrollSize) and (mp.x <= divView.size.cx) and ((mp.y >= sTop) and (mp.y <= sBottom)) then
        begin
				divView.downScrollVButton := true;
				divView.startScrollV := divView.scrollV;
        end;
      end;
    end;
	if divView.allowDragScroll then
    begin
		divView.startScrollH := divView.scrollH;
		divView.startScrollV := divView.scrollV;
    end;
end;

procedure TouchUpDiv(var divView:FCView; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
begin
  divView.downScrollHButton := false;
	divView.downScrollVButton := false;
	divView.hoverScrollHButton := false;
	divView.hoverScrollVButton := false;
end;

procedure TouchWheelDiv(var divView:FCView; delta:integer);
var
  oldScrollV:double;
  contentHeight:double;
begin
  oldScrollV := divView.scrollV;
	if delta > 0 then
		oldScrollV := oldScrollV - 10
	else if delta < 0 then
    begin
		oldScrollV := oldScrollV + 10;
    end;
	contentHeight := GetDivContentHeight(divView);
	if contentHeight < divView.size.cy then
		divView.scrollV := 0
	else
    begin
		if oldScrollV < 0 then
			oldScrollV := 0
		else if oldScrollV > contentHeight - divView.size.cy then
      begin
			oldScrollV := contentHeight - divView.size.cy;
      end;
		divView.scrollV := oldScrollV;
    end;
end;

procedure DrawDiv(var divView:FCView; var paint:FCPaint; clipRect:FCRect);
begin
  if divView.backColor <> 'none' then
		paint.FillRoundRect(divView.backColor, 0, 0, divView.size.cx, divView.size.cy, divView.cornerRadius);
end;

procedure DrawDivBorder(var divView:FCView; var paint:FCPaint; clipRect:FCRect);
begin
  if divView.borderColor <> 'none' then
		paint.DrawRoundRect(divView.borderColor, divView.borderWidth, 0, 0, 0, divView.size.cx, divView.size.cy, divView.cornerRadius);
end;

procedure FastAddGridColumns(var grid:FCGrid; var columns:array of string);
var
  oldLength:integer;
  newLength:integer;
begin
  oldLength := High(grid.columns) - Low(grid.columns) + 1;
  newLength := High(columns) - Low(columns) + 1; 
  SetLength(grid.columns, oldLength + newLength);
end;

function FastAddGridRow(var grid:FCGrid; var datas:array of string):FCGridRow;
var
  oldLength:integer;
  newLength:integer;
  i:integer;
begin
  oldLength := High(grid.rows) - Low(grid.rows) + 1;
  newLength := High(datas) - Low(datas) + 1; 
  SetLength(grid.rows, oldLength + newLength);
end;

procedure AddViewToGridCell(var inView:FCView; var cell:FCGridCell; var grid:FCGrid);
begin
  inView.displayOffset := false;
	inView.visible := false;
	//cell.view = view
	//AddViewToParent(inView, grid);
end;

function GetGridContentWidth(var grid:FCGrid):double;
var
  cWidth:double;
  length:integer;
  i:integer;
begin
  cWidth := 0;
  length := High(grid.columns) - Low(grid.columns) + 1;
  if length > 0 then
    begin
    for i := 0 to length - 1 do
    begin
      if grid.columns[i].visible then
        cWidth := cWidth + grid.columns[i].width;
    end;
    end;
  GetGridContentWidth := cWidth;
end;

function GetGridContentHeight(var grid:FCGrid):double;
var
  cHeight:double;
  length:integer;
  i:integer;
begin
  cHeight := 0;
  length := High(grid.rows) - Low(grid.rows) + 1;
  if length > 0 then
    begin
    for i := 0 to length - 1 do
    begin
      if grid.rows[i].visible then
        cHeight := cHeight + grid.rowHeight;
    end;
    end;
  GetGridContentHeight := cHeight;
end;

procedure DrawGridCell(var grid:FCGrid; var row:FCGridRow; var column:FCGridColumn; var cell:FCGridCell; var paint:FCPaint; left:double; top:double; right:double; bottom:double);
var
  showText:string;
  tSize:FCSize;
begin
  if cell.backColor <> 'none' then
    begin
		paint.FillRect(cell.backColor, left, top, right, bottom);
    end;
	if row.selected then
    begin
		if grid.selectedRowColor <> 'none' then
      begin
			paint.FillRect(grid.selectedRowColor, left, top, right, bottom);
      end;
    end;
	if cell.borderColor <> 'none' then
    begin
		paint.DrawLine(cell.borderColor, 1, 0, left, bottom - 1, right, bottom - 1);
		paint.DrawLine(cell.borderColor, 1, 0, right - 1, top, right - 1, bottom);
    end;
	if length(cell.value) > 0 then
    begin
		showText := cell.value;
		tSize := paint.TextSize(showText, cell.font);
		if tSize.cx > right - left then
			paint.DrawTextAutoEllipsis(showText, cell.textColor, cell.font, left + 2, top + grid.rowHeight / 2 - tSize.cy / 2, right - 2, top + grid.rowHeight / 2 + tSize.cy / 2)
		else
      begin
			if column.cellAlign = 'left' then
				paint.DrawText(showText, cell.textColor, cell.font, left + 2, top + grid.rowHeight / 2 - tSize.cy / 2)
			else if column.cellAlign = 'center' then
				paint.DrawText(showText, cell.textColor, cell.font, left + (right - left - tSize.cx) / 2, top + grid.rowHeight / 2 - tSize.cy / 2)
			else if column.cellAlign = 'right' then
				paint.DrawText(showText, cell.textColor, cell.font, right - tSize.cx, top + grid.rowHeight / 2 - tSize.cy / 2);
      end;
    end;
end;

procedure DrawGridColumn(var grid:FCGrid; var column:FCGridColumn; var paint:FCPaint; left:double; top:double; right:double; bottom:double);
var
  tSize:FCSize;
begin
  tSize := paint.TextSize(column.text, column.font);
	if column.backColor <> 'none' then
    begin
		paint.FillRect(column.backColor, left, top, right, bottom);
    end;
	if column.borderColor <> 'none' then
		paint.DrawRect(column.borderColor, 1, 0, left, top, right, bottom);
	paint.DrawText(column.text, column.textColor, column.font, left + (column.width - tSize.cx) / 2, top + grid.headerHeight / 2 - tSize.cy / 2);
end;

procedure DrawGrid(var grid:FCGrid; var paint:FCPaint; clipRect:FCRect);
var
  tSize:FCSize;
  cTop:double;
  colLeft:double;
  i:integer;
  columnsSize:integer;
  column:FCGridColumn;
  rowsSize:integer;
  row:FCGridRow;
  rTop:double;
  rBottom:double;
  cellsSize:integer;
  j:integer;
  cell:FCGridCell;
  gridColumn:FCGridColumn;
  n:integer;
  cellWidth:double;
  colSpan:integer;
  cellHeight:double;
  rowSpan:integer;
  spanColumn:FCGridColumn;
  spanRow:FCGridRow;
  cRect:FCRect;
begin
  cTop := -grid.scrollV + grid.headerHeight;
	colLeft := 0;
  columnsSize := High(grid.columns) - Low(grid.columns) + 1;
  for i := 0 to columnsSize - 1 do
  begin
    column := grid.columns[i];
    //if column.widthStr.length > 0
			//newWidthStr = column.widthStr.gsub('%', '')
			//grid.columns[i].width = ((newWidthStr).to_f * grid.size.cx / 100).to_i
		column.bounds := FCRect.Create(colLeft, 0, colLeft + grid.columns[i].width, grid.headerHeight);
		column.colIndex := i;
		colLeft := colLeft + column.width;
  end;
  rowsSize := High(grid.rows) - Low(grid.rows) + 1;
  for i := 0 to rowsSize - 1 do
  begin
    row := grid.rows[i];
		row.rowIndex := i;
		if row.visible then
			rTop := cTop;
			rBottom := cTop + grid.rowHeight;
      if (rBottom >= 0) and (cTop <= grid.size.cy) then
        cellsSize := High(row.cells) - Low(row.cells) + 1;
        for j := 0 to cellsSize - 1 do
        begin
          cell := row.cells[j];
          gridColumn := cell.column;
					if gridColumn.isNotEmpty = false then
						gridColumn := grid.columns[j];
          if gridColumn.visible then
          begin
						if gridColumn.frozen = false then
              begin
							cellWidth := gridColumn.width;
							colSpan := cell.colSpan;
							if colSpan > 1 then
              begin
                for n := 1 to colSpan - 1 do
                begin
									spanColumn := grid.columns[gridColumn.colIndex + n];
									if spanColumn.isNotEmpty and spanColumn.visible then
										cellWidth := cellWidth + spanColumn.width;
								end;
              end;
							cellHeight := grid.rowHeight;
							rowSpan := cell.rowSpan;
							if rowSpan > 1 then
              begin
								for n := 1 to rowSpan - 1 do
                begin
									spanRow := grid.rows[i + n];
									if spanRow.isNotEmpty and spanRow.visible then
										cellHeight := cellHeight + grid.rowHeight;
								end;
              end;
              cRect := FCRect.Create(gridColumn.bounds.left - grid.scrollH, rTop, gridColumn.bounds.left + cellWidth - grid.scrollH, rTop + cellHeight);
							if (cRect.right >= 0) and (cRect.left < grid.size.cx) then
								DrawGridCell(grid, row, gridColumn, cell, paint, cRect.left, cRect.top, cRect.right, cRect.bottom);
            end;
          end;
        end;
      for j := 0 to cellsSize - 1 do
        begin
          cell := row.cells[j];
          gridColumn := cell.column;
					if gridColumn.isNotEmpty = false then
						gridColumn := grid.columns[j];
          if gridColumn.visible then
          begin
						if gridColumn.frozen then
              begin
							cellWidth := gridColumn.width;
							colSpan := cell.colSpan;
							if colSpan > 1 then
              begin
                for n := 1 to colSpan - 1 do
                begin
									spanColumn := grid.columns[gridColumn.colIndex + n];
									if spanColumn.isNotEmpty and spanColumn.visible then
										cellWidth := cellWidth + spanColumn.width;
								end;
              end;
							cellHeight := grid.rowHeight;
							rowSpan := cell.rowSpan;
							if rowSpan > 1 then
              begin
								for n := 1 to rowSpan - 1 do
                begin
									spanRow := grid.rows[i + n];
									if spanRow.isNotEmpty and spanRow.visible then
										cellHeight := cellHeight + grid.rowHeight;
								end;
              end;
              cRect := FCRect.Create(gridColumn.bounds.left, rTop, gridColumn.bounds.left + cellWidth, rTop + cellHeight);
							if (cRect.right >= 0) and (cRect.left < grid.size.cx) then
								DrawGridCell(grid, row, gridColumn, cell, paint, cRect.left, cRect.top, cRect.right, cRect.bottom);
            end;
          end;
        end;
      if cTop > grid.size.cy then
				break;
			cTop := cTop + grid.rowHeight;
  end;
end;

procedure DrawGridScrollBar(var grid:FCGrid; var paint:FCPaint; clipRect:FCRect);
var
  contentWidth:double;
  contentHeight:double;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
  cLeft:double;
  columnsSize:integer;
  i:integer;
  gridColumn:FCGridColumn;
begin
  grid.hScrollIsVisible := false;
  grid.vScrollIsVisible := false;
  if grid.headerHeight > 0 then
    begin
    columnsSize := High(grid.columns) - Low(grid.columns) + 1;
    cLeft := -grid.scrollH;
    for i := 0 to columnsSize - 1 do 
    begin
      gridColumn := grid.columns[i];
      if gridColumn.visible then
        if gridColumn.frozen = false then
          DrawGridColumn(grid, gridColumn, paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight);
        cLeft := cLeft + gridColumn.width;
    end;
    cLeft := 0;
    for i := 0 to columnsSize - 1 do 
    begin
      gridColumn := grid.columns[i];
      if gridColumn.visible then
        if gridColumn.frozen then
          DrawGridColumn(grid, gridColumn, paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight);
        cLeft := cLeft + gridColumn.width;
    end;
    end;
  if grid.showHScrollBar then
    begin
		contentWidth := GetGridContentWidth(grid);
		if (contentWidth > 0) and (contentWidth > grid.size.cx) then
      begin
			sLeft := grid.size.cx * grid.scrollH / contentWidth;
			sRight := grid.size.cx * (grid.scrollH + grid.size.cx) / contentWidth;
			if sRight - sLeft < grid.scrollSize then
        begin
				sRight := sLeft + grid.scrollSize;
        end;
			if (touchMoveView.uid = grid.uid) and (grid.hoverScrollHButton or grid.downScrollHButton) then
				paint.FillRect(grid.scrollBarHoveredColor, sLeft, grid.size.cy - grid.scrollSize, sRight, grid.size.cy)
			else
				paint.FillRect(grid.scrollBarColor, sLeft, grid.size.cy - grid.scrollSize, sRight, grid.size.cy);
      grid.hScrollIsVisible := true;
      end;
    end;
	if grid.showVScrollBar then
    begin
		contentHeight := GetGridContentHeight(grid);
		if (contentHeight > 0) and (contentHeight > grid.size.cy - grid.headerHeight) and (contentHeight > 0) and (grid.size.cy - grid.headerHeight - grid.scrollSize > 0) then
      begin
			sTop := grid.headerHeight + (grid.size.cy - grid.headerHeight - grid.scrollSize) * grid.scrollV / contentHeight;
			sBottom := sTop + (grid.size.cy - grid.headerHeight - grid.scrollSize) * (grid.size.cy - grid.headerHeight - grid.scrollSize) / contentHeight;
				if sBottom - sTop < grid.scrollSize then
        begin
				sBottom := sTop + grid.scrollSize;
        end;
			if (touchMoveView.uid = grid.uid) and (grid.hoverScrollVButton or grid.downScrollVButton) then
				paint.FillRect(grid.scrollBarHoveredColor, grid.size.cx - grid.scrollSize, sTop, grid.size.cx, sBottom)
			else
				paint.FillRect(grid.scrollBarColor, grid.size.cx - grid.scrollSize, sTop, grid.size.cx, sBottom);
      grid.vScrollIsVisible := true;
      end;
    end;
end;

procedure TouchMoveGrid(var grid:FCGrid; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint);
var
  gridColumn:FCGridColumn;
  newWidth:double;
  paint:FCPaint;
  mp:FCPoint;
  contentWidth:double;
  subX:double;
  newScrollH:double;
  contentHeight:double;
  subY:double;
  newScrollV:double;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
begin
  paint := grid.GetPaint();
  grid.hoverScrollHButton := false;
	grid.hoverScrollVButton := false;
  if paint.resizeColumnState <> 0 then
    begin
		gridColumn := grid.columns[paint.resizeColumnIndex];
		newWidth := paint.resizeColumnBeginWidth + (firstPoint.x - grid.startPoint.x);
		if newWidth > 10 then
			gridColumn.width := newWidth;
    end;
  mp := firstPoint;
  if firstTouch then
    begin
    if grid.showHScrollBar or grid.showVScrollBar then
      if grid.downScrollHButton then
        begin
        contentWidth := GetGridContentWidth(grid);
        subX := contentWidth * (mp.x - grid.startPoint.x) / grid.size.cx;
        newScrollH := grid.startScrollH + subX;
        if newScrollH < 0 then
          newScrollH := 0
        else if newScrollH > contentWidth - grid.size.cx then
          begin
          newScrollH := contentWidth - grid.size.cx;
          end;
        grid.scrollH := newScrollH;
        paint.cancelClick := true;
        end
      else if grid.downScrollVButton then
        begin
        contentHeight := GetGridContentHeight(grid);
        subY := contentHeight * (mp.y - grid.startPoint.y) / (grid.size.cy - grid.headerHeight - grid.scrollSize);
        newScrollV := grid.startScrollV + subY;
        if newScrollV < 0 then
          newScrollV := 0
        else if newScrollV > contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize) then
          begin
          newScrollV := contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize);
          end;
        grid.scrollV := newScrollV;
        paint.cancelClick := true;
        end;
    if grid.allowDragScroll then
      begin
      contentWidth := GetGridContentWidth(grid);
      if contentWidth > grid.size.cx - grid.scrollSize then
        begin
        subX := grid.startPoint.x - mp.x;
        newScrollH := grid.startScrollH + subX;
        if newScrollH < 0 then
          newScrollH := 0
        else if newScrollH > contentWidth - grid.size.cx then
          begin
          newScrollH := contentWidth - grid.size.cx;
          end;
        grid.scrollH := newScrollH;
        if Abs(subX) > 5 then
          paint.cancelClick := true;
        end;
      contentHeight := GetGridContentHeight(grid);
      if contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize then
        begin
        subY := grid.startPoint.y - mp.y;
        newScrollV := grid.startScrollV + subY;
        if newScrollV < 0 then
          newScrollV := 0
        else if newScrollV > contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize) then
          newScrollV := contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize);
        grid.scrollV := newScrollV;
        if Abs(subY) > 5 then
          paint.cancelClick := true;
        end;
      end;
    end
  else
    begin
		if grid.showHScrollBar then
      begin
			contentWidth := GetGridContentWidth(grid);
			if (contentWidth > 0) and (contentWidth > grid.size.cx - grid.scrollSize) then
        begin
				sLeft := grid.size.cx * grid.scrollH / contentWidth;
				sRight := grid.size.cx * (grid.scrollH + grid.size.cx) / contentWidth;
				if sRight - sLeft < grid.scrollSize then
          begin
					sRight := sLeft + grid.scrollSize;
          end;
				if (mp.x >= sLeft) and (mp.x <= sRight) and (mp.y >= grid.size.cy - grid.scrollSize) and (mp.y <= grid.size.cy) then
					grid.hoverScrollHButton := true
				else
					grid.hoverScrollHButton := false;
        end;
      end;
		if grid.showVScrollBar then
      begin
			contentHeight := GetGridContentHeight(grid);
			if (contentHeight > 0) and (contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize) then
        begin
				sTop := grid.headerHeight + (grid.size.cy - grid.headerHeight - grid.scrollSize) * grid.scrollV / contentHeight;
				sBottom := grid.headerHeight + (grid.size.cy - grid.headerHeight - grid.scrollSize) * (grid.scrollV + (grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight;
				if sBottom - sTop < grid.scrollSize then
          begin
					sBottom := sTop + grid.scrollSize;
          end;
				if (mp.x >= grid.size.cx - grid.scrollSize) and (mp.x <= grid.size.cx) and (mp.y >= sTop) and (mp.y <= sBottom) then
					grid.hoverScrollVButton := true
				else
					grid.hoverScrollVButton := false;
        end;
      end;
    end;
end;

procedure TouchDownGrid(var grid:FCGrid; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
var
  paint:FCPaint;
  mp:FCPoint;
  contentWidth:double;
  sLeft:double;
  sRight:double;
  contentHeight:double;
  sTop:double;
  sBottom:double;
  colLeft:double;
  columnsSize:integer;
  i:integer;
  column:FCGridColumn;
  gridColumn:FCGridColumn;
  bounds:FCRect;
begin
  paint := grid.GetPaint();
  mp := firstPoint;
	grid.startPoint := mp;
	grid.downScrollHButton := false;
	grid.downScrollVButton := false;
	grid.hoverScrollHButton := false;
	grid.hoverScrollVButton := false;
  if grid.showHScrollBar then
    begin
		contentWidth := GetGridContentWidth(grid);
		if (contentWidth > 0) and (contentWidth > grid.size.cx - grid.scrollSize) then
      begin
			sLeft := grid.size.cx * grid.scrollH / contentWidth;
			sRight := grid.size.cx * (grid.scrollH + grid.size.cx) / contentWidth;
			if sRight - sLeft < grid.scrollSize then
        begin
				sRight := sLeft + grid.scrollSize;
        end;
			if (mp.x >= sLeft) and (mp.x <= sRight) and (mp.y >= grid.size.cy - grid.scrollSize) and (mp.y <= grid.size.cy) then
        begin
				grid.downScrollHButton := true;
				grid.startScrollH := grid.scrollH;
        end;
      end;
    end;
	if grid.showVScrollBar then
    begin
		contentHeight := GetGridContentHeight(grid);
		if (contentHeight > 0) and (contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize) then
      begin
			sTop := grid.headerHeight + (grid.size.cy - grid.headerHeight - grid.scrollSize) * grid.scrollV / contentHeight;
			sBottom := grid.headerHeight + (grid.size.cy - grid.headerHeight - grid.scrollSize) * (grid.scrollV + (grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight;
			if sBottom - sTop < grid.scrollSize then
        begin
				sBottom := sTop + grid.scrollSize;
        end;
			if (mp.x >= grid.size.cx - grid.scrollSize) and (mp.x <= grid.size.cx) and (mp.y >= sTop) and (mp.y <= sBottom) then
        begin
				grid.downScrollVButton := true;
				grid.startScrollV := grid.scrollV;
        end;
      end;
    end;
	if grid.allowDragScroll then
    begin
		grid.startScrollH := grid.scrollH;
		grid.startScrollV := grid.scrollV;
    end;
  colLeft := 0; 
  columnsSize := High(grid.columns) - Low(grid.columns) + 1;
  for i := 0 to columnsSize - 1 do
  begin
    column := grid.columns[i];
		column.bounds := FCRect.Create(colLeft, 0, colLeft + grid.columns[i].width, grid.headerHeight);
		column.colIndex := i;
		colLeft := colLeft + column.width;
  end;
  paint.resizeColumnState := 0;
	paint.resizeColumnBeginWidth := 0;
	if (grid.headerHeight > 0) and (mp.y <= grid.headerHeight) then
		for i := 0 to columnsSize - 1 do
      begin
			gridColumn := grid.columns[i];
			if gridColumn.visible then
        begin
				bounds := gridColumn.bounds;
				if (mp.x >= bounds.left - grid.scrollH) and (mp.x <= bounds.right - grid.scrollH) then
          begin
					if (gridColumn.colIndex > 0) and (mp.x < bounds.left + 5 - grid.scrollH) then
            begin
						paint.resizeColumnState := 1;
						paint.resizeColumnBeginWidth := grid.columns[gridColumn.colIndex - 1].bounds.right - grid.columns[gridColumn.colIndex - 1].bounds.left;
						paint.resizeColumnIndex := gridColumn.colIndex - 1;
            end
					else if mp.x > bounds.right - 5 - grid.scrollH then
            begin
						paint.resizeColumnState := 2;
						paint.resizeColumnBeginWidth := bounds.right - bounds.left;
						paint.resizeColumnIndex := gridColumn.colIndex;
            end;
					break
          end;
        end;
      end;
end;

procedure TouchUpGrid(var grid:FCGrid; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
var
  cTop:double;
  colLeft:double;
  i:integer;
  rowsSize:integer;
  row:FCGridRow;
  rTop:double;
  rBottom:double;
  cellsSize:integer;
  j:integer;
  cell:FCGridCell;
  gridColumn:FCGridColumn;
  n:integer;
  cellWidth:double;
  colSpan:integer;
  cellHeight:double;
  rowSpan:integer;
  spanColumn:FCGridColumn;
  spanRow:FCGridRow;
  cRect:FCRect;
  s:integer;
begin
  grid.downScrollHButton := false;
	grid.downScrollVButton := false;
	grid.hoverScrollHButton := false;
	grid.hoverScrollVButton := false;
  cTop := -grid.scrollV + grid.headerHeight;
	colLeft := 0;
  rowsSize := High(grid.rows) - Low(grid.rows) + 1;
  for i := 0 to rowsSize - 1 do
  begin
    row := grid.rows[i];
		row.rowIndex := i;
		if row.visible then
			rTop := cTop;
			rBottom := cTop + grid.rowHeight;
      if (rBottom >= 0) and (cTop <= grid.size.cy) then
        cellsSize := High(row.cells) - Low(row.cells) + 1;
        for j := 0 to cellsSize - 1 do
        begin
          cell := row.cells[j];
          gridColumn := cell.column;
          if gridColumn.isNotEmpty = false then
            gridColumn := grid.columns[j];
          if gridColumn.visible then
          begin
            if gridColumn.frozen then
              begin
              cellWidth := gridColumn.width;
              colSpan := cell.colSpan;
              if colSpan > 1 then
              begin
                for n := 1 to colSpan - 1 do
                begin
                  spanColumn := grid.columns[gridColumn.colIndex + n];
                  if spanColumn.isNotEmpty and spanColumn.visible then
                    cellWidth := cellWidth + spanColumn.width;
                end;
              end;
              cellHeight := grid.rowHeight;
              rowSpan := cell.rowSpan;
              if rowSpan > 1 then
              begin
                for n := 1 to rowSpan - 1 do
                begin
                  spanRow := grid.rows[i + n];
                  if spanRow.isNotEmpty and spanRow.visible then
                    cellHeight := cellHeight + grid.rowHeight;
                end;
              end;
              cRect := FCRect.Create(gridColumn.bounds.left, rTop, gridColumn.bounds.left + cellWidth, rTop + cellHeight);
              if (cRect.right >= 0) and (cRect.left < grid.size.cx) then
              begin
                if (firstPoint.x >= cRect.left) and (firstPoint.x <= cRect.right) and (firstPoint.y >= cRect.top) and (firstPoint.y <= cRect.bottom) then
                  begin
                    for s := 0 to rowsSize - 1 do
                    begin
                      if s = i then
                        grid.rows[s].selected := true
                      else 
                        grid.rows[s].selected := false;
                    end;
                  end;
              end;
            end;
          end;
        end;
        for j := 0 to cellsSize - 1 do
        begin
          cell := row.cells[j];
          gridColumn := cell.column;
					if gridColumn.isNotEmpty = false then
						gridColumn := grid.columns[j];
          if gridColumn.visible then
          begin
						if gridColumn.frozen = false then
              begin
							cellWidth := gridColumn.width;
							colSpan := cell.colSpan;
							if colSpan > 1 then
              begin
                for n := 1 to colSpan - 1 do
                begin
									spanColumn := grid.columns[gridColumn.colIndex + n];
									if spanColumn.isNotEmpty and spanColumn.visible then
										cellWidth := cellWidth + spanColumn.width;
								end;
              end;
							cellHeight := grid.rowHeight;
							rowSpan := cell.rowSpan;
							if rowSpan > 1 then
              begin
								for n := 1 to rowSpan - 1 do
                begin
									spanRow := grid.rows[i + n];
									if spanRow.isNotEmpty and spanRow.visible then
										cellHeight := cellHeight + grid.rowHeight;
								end;
              end;
              cRect := FCRect.Create(gridColumn.bounds.left - grid.scrollH, rTop, gridColumn.bounds.left + cellWidth - grid.scrollH, rTop + cellHeight);
              if (cRect.right >= 0) and (cRect.left < grid.size.cx) then
              begin
                if (firstPoint.x >= cRect.left) and (firstPoint.x <= cRect.right) and (firstPoint.y >= cRect.top) and (firstPoint.y <= cRect.bottom) then
                  begin
                    for s := 0 to rowsSize - 1 do
                    begin
                      if s = i then
                        begin
                        grid.rows[s].selected := true;
                        end
                      else 
                        begin
                        grid.rows[s].selected := false;
                        end;
                    end;
                  end;
              end;
            end;
          end;
        end;
      if cTop > grid.size.cy then
				break;
			cTop := cTop + grid.rowHeight;
  end;
end;

procedure TouchWheelGrid(var grid:FCGrid; delta:integer);
var
  oldScrollV:double;
  contentHeight:double;
begin
  oldScrollV := grid.scrollV;
	if delta > 0 then
		oldScrollV := oldScrollV - 10
	else if delta < 0 then
    begin
		oldScrollV := oldScrollV + 10;
    end;
	contentHeight := GetGridContentHeight(grid);
	if contentHeight < grid.size.cy then
		grid.scrollV := 0
	else
    begin
		if oldScrollV < 0 then
			oldScrollV := 0
		else if oldScrollV > contentHeight - grid.size.cy then
      begin
			oldScrollV := contentHeight - grid.size.cy;
      end;
		grid.scrollV := oldScrollV;
    end;
end;

procedure ResetSplitLayoutDiv(var split:FCSplitLayoutDiv);
var
  splitRect:FCRect;
  width:double;
	height:double;
	fRect:FCRect;
	sRect:FCRect;
	splitterSize:FCSize;
  spRect2:FCRect;
  fcRect2:FCRect;
  scRect:FCRect;
  layoutStyle:string;
begin
  splitRect := FCRect.Create(0, 0, 0, 0);
	width := split.size.cx;
	height := split.size.cy;
	fRect := FCRect.Create(0, 0, 0, 0);
	sRect := FCRect.Create(0, 0, 0, 0);
	splitterSize := FCSize.Create(0, 0);
	if split.splitter.visible then
    begin
		splitterSize.cx := split.splitter.size.cx;
		splitterSize.cy := split.splitter.size.cy;
	  end;
  split.splitter.topMost := true;
	layoutStyle := split.layoutStyle;
	if layoutStyle = 'bottomtotop' then
    begin
		if (split.splitMode = 'absolutesize') or (split.oldSize.cy = 0) then
      begin
			splitRect.left := 0;
			splitRect.top := height - (split.oldSize.cy - split.splitter.location.y);
			splitRect.right := width;
			splitRect.bottom := splitRect.top + splitterSize.cy;
      end
		else if split.splitMode = 'percentsize' then
      begin
			splitRect.left := 0;
			if split.splitPercent = -1 then
        begin
				split.splitPercent := split.splitter.location.y / split.oldSize.cy;
        end;
			splitRect.top := height * split.splitPercent;
			splitRect.right := width;
			splitRect.bottom := splitRect.top + splitterSize.cy;
		  end;
		fRect.left := 0;
		fRect.top := splitRect.bottom;
		fRect.right := width;
		fRect.bottom := height;
		sRect.left := 0;
		sRect.top := 0;
		sRect.right := width;
		sRect.bottom := splitRect.top;
    end
	else if layoutStyle = 'lefttoright' then
    begin
		if (split.splitMode = 'absolutesize') or (split.oldSize.cx = 0) then
      begin
			splitRect.left := split.splitter.location.x;
			splitRect.top := 0;
			splitRect.right := splitRect.left + splitterSize.cx;
			splitRect.bottom := height;
      end
		else if split.splitMode = 'percentsize' then
      begin
			if split.splitPercent = -1 then
        begin
				split.splitPercent := split.splitter.location.x / split.oldSize.cx;
			  end;
			splitRect.left := width * split.splitPercent;
			splitRect.top := 0;
			splitRect.right := splitRect.left + splitterSize.cx;
			splitRect.bottom := height;
      end;
		fRect.left := 0;
		fRect.top := 0;
		fRect.right := splitRect.left;
		fRect.bottom := height;
		sRect.left := splitRect.right;
		sRect.top := 0;
		sRect.right := width;
		sRect.bottom := height;
    end
	else if layoutStyle = 'righttoleft' then
    begin
		if (split.splitMode = 'absolutesize') or (split.oldSize.cx = 0) then
      begin
			splitRect.left := width - (split.oldSize.cx - split.splitter.location.x);
			splitRect.top := 0;
			splitRect.right := splitRect.left + splitterSize.cx;
			splitRect.bottom := height;
      end
		else if split.splitMode = 'percentsize' then
      begin
			if split.splitPercent = -1 then
        begin
				split.splitPercent := split.splitter.location.x / split.oldSize.cx;
			  end;
			splitRect.left := width * split.splitPercent;
			splitRect.top := 0;
			splitRect.right := splitRect.left + splitterSize.cx;
			splitRect.bottom := height;
      end;
		fRect.left := splitRect.right;
		fRect.top := 0;
		fRect.right := width;
		fRect.bottom := height;
		sRect.left := 0;
		sRect.top := 0;
		sRect.right := splitRect.left;
		sRect.bottom := height;
    end
	else if layoutStyle = 'toptobottom' then
    begin
		if (split.splitMode = 'absolutesize') or (split.oldSize.cy = 0) then
      begin
			splitRect.left := 0;
			splitRect.top := split.splitter.location.y;
			splitRect.right := width;
			splitRect.bottom := splitRect.top + splitterSize.cy;
      end
		else if split.splitMode = 'percentsize' then
      begin
			splitRect.left := 0;
			if split.splitPercent = -1 then
        begin
				split.splitPercent := split.splitter.location.y / split.oldSize.cy;
			  end;
			splitRect.top := height * split.splitPercent;
			splitRect.right := width;
			splitRect.bottom := splitRect.top + splitterSize.cy;
		  end;
		fRect.left := 0;
		fRect.top := 0;
		fRect.right := width;
		fRect.bottom := splitRect.top;
		sRect.left := 0;
		sRect.top := splitRect.bottom;
		sRect.right := width;
		sRect.bottom := height;
	  end;
	if split.splitter.visible then
    begin
		spRect2 := FCRect.Create(split.splitter.location.x,  split.splitter.location.y, split.splitter.location.x + split.splitter.size.cx, split.splitter.location.y + split.splitter.size.cy);
		if (spRect2.left <> splitRect.left) or (spRect2.top <> splitRect.top) or (spRect2.right <> splitRect.right) or (spRect2.bottom <> splitRect.bottom) then
			split.splitter.location := FCPoint.Create(splitRect.left, splitRect.top);
			split.splitter.size := FCSize.Create(splitRect.right - splitRect.left, splitRect.bottom - splitRect.top);
    end;
	fcRect2 := FCRect.Create(split.firstView.location.x,  split.firstView.location.y, split.firstView.location.x + split.firstView.size.cx, split.firstView.location.y + split.firstView.size.cy);
	if (fcRect2.left <>  fRect.left) or (fcRect2.top <> fRect.top) or (fcRect2.right <> fRect.right) or (fcRect2.bottom <> fRect.bottom) then
    begin
		split.firstView.location := FCPoint.Create(fRect.left, fRect.top);
		split.firstView.size := FCSize.Create(fRect.right - fRect.left, fRect.bottom - fRect.top);
    end;
	scRect := FCRect.Create(split.secondView.location.x,  split.secondView.location.y, split.secondView.location.x + split.secondView.size.cx, split.secondView.location.y + split.secondView.size.cy);
	if (scRect.left <> sRect.left) or (scRect.top <> sRect.top) or (scRect.right <> sRect.right) or (scRect.bottom <>  sRect.bottom) then
    begin
		split.secondView.location := FCPoint.Create(sRect.left, sRect.top);
		split.secondView.size := FCSize.Create(sRect.right - sRect.left, sRect.bottom - sRect.top);
    end;
	split.oldSize := FCSize.Create(width, height);
end;

procedure ResetLayoutDiv(var layout:FCLayoutDiv);
var
  padding:FCPadding;
  vPos:integer;
  left:double;
  top:double;
  width:double;
  height:double;
  i:integer;
  subViews:viewArray;
  subViewsSize:integer;
  vView:FCView;
  size:FCSize;
  margin:FCPadding;
  cLeft:double;
  cTop:double;
  cWidth:double;
  cHeight:double;
  nLeft:double;
  nTop:double;
  nWidth:double;
  nHeight:double;
  lWidth:double;
  lHeight:double;
  lTop:double;
  lBottom:double;
  lRight:double;
  lLeft:double;
begin
  padding := layout.padding;
	vPos := 0;
	left := padding.left;
	top := padding.top;
	width := layout.size.cx - padding.left - padding.right;
	height := layout.size.cy - padding.top - padding.bottom;
	subViews := layout.views;
  subViewsSize := High(subViews) - Low(subViews) + 1;
  for i := 0 to subViewsSize - 1 do
  begin
    vView := subViews[i];
    if vView.visible then
      begin
			size := FCSize.Create(vView.size.cx, vView.size.cy);
			margin := vView.margin;
			cLeft := vView.location.x;
			cTop := vView.location.y;
			cWidth := size.cx;
			cHeight := size.cy;
			nLeft := cLeft;
			nTop := cTop;
			nWidth := cWidth;
			nHeight := cHeight;
			if layout.layoutStyle = 'bottomtotop' then
        begin
				if i = 0 then
          begin
					top := height - padding.top;
          end;
				lWidth := 0;
				if layout.autoWrap then
          begin
					lWidth := size.cx;
					lTop := top - margin.top - cHeight - margin.bottom;
					if lTop < padding.top then
            begin
						if vPos <> 0 then
              begin
							left := left + cWidth + margin.left;
              end;
						top := height - padding.top;
            end;
          end
				else
          begin
					lWidth := width - margin.left - margin.right;
          end;
				top := top - (cHeight + margin.bottom);
				nLeft := left + margin.left;
				nWidth := lWidth;
				nTop := top;
        end
			else if layout.layoutStyle = 'lefttoright' then
        begin
				lHeight := 0;
				if layout.autoWrap then
          begin
					lHeight := size.cy;
					lRight := left + margin.left + cWidth + margin.right;
					if lRight > width then
            begin
						left := padding.left;
						if vPos <> 0 then
							top := top + cHeight + margin.top;
            end;
          end
				else
          begin
					lHeight := height - margin.top - margin.bottom;
          end;
				left := left + margin.left;
				nLeft := left;
				nTop := top + margin.top;
				nHeight := lHeight;
				left := left + cWidth + margin.right;
        end
			else if layout.layoutStyle = 'righttoleft' then
        begin
				if i = 0 then
          begin
					left := width - padding.left;
          end;
				lHeight := 0;
				if layout.autoWrap then
          begin
					lHeight := size.cy;
					lLeft := left - margin.left - cWidth - margin.right;
					if lLeft < padding.left then
            begin
						left := width - padding.left;
						if vPos <> 0 then
							top :=  top + cHeight + margin.top;
            end;
          end
				else
          begin
					lHeight := height - margin.top - margin.bottom;
          end;
				left := left - (cWidth + margin.left);
				nLeft := left;
				nTop := top + margin.top;
				nHeight := lHeight
        end
			else if layout.layoutStyle = 'toptobottom' then
        begin
				lWidth := 0;
				if layout.autoWrap then
          begin
					lWidth := size.cx;
					lBottom := top + margin.top + cHeight + margin.bottom;
					if lBottom > height then
            begin
						if vPos <> 0 then
							left := left + cWidth + margin.left + margin.right;
						top := padding.top;
            end;
          end
				else
          begin
					lWidth := width - margin.left - margin.right;
          top := top + margin.top;
          nTop := top;
          nLeft := left + margin.left;
          nWidth := lWidth;
          top := top + cHeight + margin.bottom;
          end;
        end;
			if (cLeft <> nLeft) or (cTop <> nTop) or (cWidth <> nWidth) or (cHeight <> nHeight) then
        begin
				vView.location := FCPoint.Create(nLeft, nTop);
				vView.size := FCSize.Create(nWidth, nHeight);
        end;
			vPos := vPos + 1;
      end;
  end;
end;

procedure UpdataPageLayout(var tabView:FCTabView; tabPage:FCTabPage; left:double;
    top:double; width:double; height:double; tw:double; th:double);
var 
  newBounds:FCRect;
begin
  newBounds := FCRect.Create(0, 0, 0, 0);
	if tabView.layout = 'bottom' then
    begin
		newBounds.left := 0;
		newBounds.top := 0;
		newBounds.right := width;
		newBounds.bottom := height - th;
		tabPage.headerButton.location := FCPoint.Create(left, height - th);
    end
	else if tabView.layout = 'left' then
    begin
		newBounds.left := tw;
		newBounds.top := 0;
		newBounds.right := width;
		newBounds.bottom := height;
		tabPage.headerButton.location := FCPoint.Create(0, top);
    end
	else if tabView.layout = 'right' then
    begin
		newBounds.left := 0;
		newBounds.top := 0;
		newBounds.right := width - tw;
		newBounds.bottom := height;
		tabPage.headerButton.location := FCPoint.Create(width - tw, top);
    end
	else if tabView.layout = 'top' then
    begin
		newBounds.left := 0;
		newBounds.top := th;
		newBounds.right := width;
		newBounds.bottom := height;
		tabPage.headerButton.location := FCPoint.Create(left, 0);
    end;
	tabPage.location := FCPoint.Create(newBounds.left, newBounds.top);
	tabPage.size := FCSize.Create(newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
end;

procedure UpdateTabLayout(var tabView:FCTabView);
var
  width:double;
  height:double;
  left:double;
  top:double;
  tabPagesLength:integer;
  i:integer;
  tabPage:FCTabPage;
  headerButton:FCView;
  tw:double;
  th:double;
begin
  width := tabView.size.cx;
	height := tabView.size.cy;
	left := 0;
	top := 0;
  tabPagesLength := High(tabView.tabPages) - Low(tabView.tabPages) + 1;
  for i := 0 to tabPagesLength - 1 do
  begin
    tabPage := tabView.tabPages[i];
    headerButton := tabPage.headerButton;
    if headerButton.visible then
      begin
      tw := headerButton.size.cx;
      th := headerButton.size.cy;
      UpdataPageLayout(tabView, tabPage, left, top, width, height, tw, th);
			left := left + tw;
			top := top + th;
      end
    else
      tabPage.visible := false;
  end;
end;

procedure AddTabPage(var tabView:FCTabView; var tabPage:FCTabPage; var tButton:FCView);
var
  tabPagesLength:integer;
begin
  tabPage.headerButton := tButton;
	tabPage.SetParent(tabView);
	tabPage.SetPaint(tabView.GetPaint());
	tButton.SetParent(tabView);
	tButton.SetPaint(tabView.GetPaint());
  tabPagesLength := High(tabView.tabPages) - Low(tabView.tabPages) + 1;
  SetLength(tabView.tabPages, tabPagesLength + 1);
  tabView.tabPages[tabPagesLength] := tabPage;
  AddViewToParent(FCView(tabPage), FCView(tabView));
  AddViewToParent(tButton, FCView(tabView));
end;

procedure RemoveTabPage(var tabView:FCTabView; var tabPage:FCTabPage);
begin
end;

procedure SelectTabPage(var tabView:FCTabView; var tabPage:FCTabPage);
var
  tabPagesLength:integer;
  i:integer;
  tp:FCTabPage;
begin
  tabPagesLength := High(tabView.tabPages) - Low(tabView.tabPages) + 1;
  for i := 0 to tabPagesLength - 1 do
  begin
    tp := tabView.tabPages[i];
    if tp.uid = tabPage.uid then
      tp.visible := true
    else
      tp.visible := false;
  end;
  UpdateTabLayout(tabView);
end;

procedure DrawTabViewBorder(var tabView:FCTabView; var paint:FCPaint; clipRect:FCRect);
var
  tabPagesLength:integer;
  i:integer;
  tp:FCTabPage;
  headerButton:FCView;
  location:FCPoint;
  size:FCSize;
begin
  if tabView.underLineColor <> 'none' then
    tabPagesLength := High(tabView.tabPages) - Low(tabView.tabPages) + 1;
    for i := 0 to tabPagesLength - 1 do
    begin
      tp := tabView.tabPages[i];
      if tp.visible then
        begin
        headerButton := tp.headerButton;
        location := FCPoint.Create(headerButton.location.x, headerButton.location.y);
				size := headerButton.size;
				if tabView.useAnimation then
          begin
					if tabView.underPoint.isNotEmpty then
						location.x := tabView.underPoint.x;
						location.y := tabView.underPoint.y;
          end;
        if tabView.layout = 'bottom' then
					paint.FillRect(tabView.underLineColor, location.x, location.y, location.x + size.cx, location.y + tabView.underLineSize)
				else if tabView.layout = 'left' then
					paint.FillRect(tabView.underLineColor, location.x + size.cx - tabView.underLineSize, location.y, location.x + size.cx, location.y + size.cy)
				else if tabView.layout = 'top' then
					paint.FillRect(tabView.underLineColor, location.x, location.y + size.cy - tabView.underLineSize, location.x + size.cx, location.y + size.cy)
				else if  tabView.layout = 'right' then
					paint.FillRect(tabView.underLineColor, location.x, location.y, location.x + tabView.underLineSize, location.y + size.cy);
        end;
    end;
end;

function GetTreeContentWidth(var tree:FCTree):double;
var
  cWidth:double;
  length:integer;
  i:integer;
begin
  cWidth := 0;
  length := High(tree.columns) - Low(tree.columns) + 1;
  if length > 0 then
    begin
    for i := 0 to length - 1 do
      begin
        if tree.columns[i].visible then
          cWidth := cWidth + tree.columns[i].width;
      end;
    end;
  GetTreeContentWidth := cWidth;
end;

function GetTreeContentHeight(var tree:FCTree):double;
var
  cHeight:double;
  length:integer;
  i:integer;
begin
  cHeight := 0;
  length := High(tree.rows) - Low(tree.rows) + 1;
  if length > 0 then
    begin
    for i := 0 to length - 1 do
      begin
        if tree.rows[i].visible then
          cHeight := cHeight + tree.rowHeight;
      end;
    end;
  GetTreeContentHeight := cHeight;
end;

function GetTotalIndent(var node:FCTreeNode):double;
var
  pNode:FCTreeNode;
begin
  pNode := node.GetParentNode();
  if pNode.isNotEmpty then
    GetTotalIndent := node.indent + GetTotalIndent(pNode)
  else
    GetTotalIndent := node.indent;
end;

procedure DrawTreeNode(var tree:FCTree; var row:FCTreeRow; var column:FCTreeColumn; var node:FCTreeNode; var paint:FCPaint; left:double; top:double; right:double; bottom:double);
var
  tSize:FCSize;
  tLeft:double;
  wLeft:double;
  cR:double;
  childNodeLength:integer;
  drawPoints:array of FCPoint;
begin
  if node.backColor <> 'none' then
		paint.FillRect(node.backColor, left, top, right, bottom);
  if row.selected then
    begin
		if tree.selectedRowColor <> 'none' then
      begin
			paint.FillRect(tree.selectedRowColor, left, top, right, bottom);
      end;
    end;
	if length(node.value) > 0 then
    begin
		tSize := paint.TextSize(node.value, node.font);
		tLeft := left + 2 + GetTotalIndent(node);
		wLeft := tLeft;
		cR := tree.checkBoxWidth / 3;
		if tree.showCheckBox then
      begin
			wLeft := wLeft + tree.checkBoxWidth;
			if node.checked then
				paint.FillRect(node.textColor, tLeft + (tree.checkBoxWidth - cR) / 2, top + (tree.rowHeight - cR) / 2, tLeft + (tree.checkBoxWidth + cR) / 2, top + (tree.rowHeight + cR) / 2)
			else
				paint.DrawRect(node.textColor, 1, 0, tLeft + (tree.checkBoxWidth - cR) / 2, top + (tree.rowHeight - cR) / 2, tLeft + (tree.checkBoxWidth + cR) / 2, top + (tree.rowHeight + cR) / 2);
      end;
    childNodeLength := High(node.childNodes) - Low(node.childNodes) + 1;
    if childNodeLength > 0 then
      begin
      SetLength(drawPoints, 3);
      if node.collapsed then
        begin
				drawPoints[0] := FCPoint.Create(wLeft + (tree.collapsedWidth + cR) / 2, top + tree.rowHeight / 2);
				drawPoints[1] := FCPoint.Create(wLeft + (tree.collapsedWidth - cR) / 2, top + (tree.rowHeight - cR) / 2);
				drawPoints[2] := FCPoint.Create(wLeft + (tree.collapsedWidth - cR) / 2, top + (tree.rowHeight + cR) / 2);
        end
			else
        begin
				drawPoints[0] := FCPoint.Create(wLeft + (tree.collapsedWidth - cR) / 2, top + (tree.rowHeight - cR) / 2);
				drawPoints[1] := FCPoint.Create(wLeft + (tree.collapsedWidth + cR) / 2, top + (tree.rowHeight - cR) / 2);
				drawPoints[2] := FCPoint.Create(wLeft + tree.collapsedWidth / 2, top + (tree.rowHeight + cR) / 2);
        end;
			paint.FillPolygon(node.textColor, drawPoints);
			wLeft := wLeft + tree.collapsedWidth;
      end;
		if tSize.cx > column.width then
			paint.DrawTextAutoEllipsis(node.value, node.textColor, node.font, wLeft, top + tree.rowHeight / 2 - tSize.cy / 2, wLeft + column.width, top + tree.rowHeight / 2 - tSize.cy / 2)
		else
			paint.DrawText(node.value, node.textColor, node.font, wLeft, top + tree.rowHeight / 2 - tSize.cy / 2);
    end;
end;

procedure DrawTree(var tree:FCTree; var paint:FCPaint; clipRect:FCRect);
var
  cLeft:double;
  cTop:double;
  colLeft:double;
  columnsSize:integer;
  i:integer;
  j:integer;
  rowsSize:integer;
  row:FCTreeRow;
  rTop:double;
  rBottom:double;
  node:FCTreeNode;
  cellsSize:integer;
  nodeWidth:double;
  nodeHeight:double;
  cRect:FCRect;
begin
  columnsSize := High(tree.columns) - Low(tree.columns) + 1;
  cTop := -tree.scrollV + tree.headerHeight;
  colLeft := 0;
  for i := 0 to columnsSize - 1 do
  begin
		tree.columns[i].bounds := FCRect.Create(colLeft, 0, colLeft + tree.columns[i].width, tree.headerHeight);
		tree.columns[i].colIndex := i;
		colLeft := colLeft + tree.columns[i].width;
	end;
  rowsSize := High(tree.rows) - Low(tree.rows) + 1;
  for i := 0 to rowsSize - 1 do
  begin
    row := tree.rows[i];
    if row.visible then
      begin
			rTop := cTop;
			rBottom := cTop + tree.rowHeight;
			if (rBottom >= 0) and (cTop <= tree.size.cy) then
        begin
        cellsSize := High(row.cells) - Low(row.cells) + 1;
        node := row.cells[j];
        nodeWidth := tree.size.cx;
				nodeHeight := tree.rowHeight;
        cRect := FCRect.Create(tree.columns[0].bounds.left - tree.scrollH, rTop, tree.columns[0].bounds.left + nodeWidth - tree.scrollH, rTop + nodeHeight);
        if (cRect.right >= 0) and (cRect.left < tree.size.cx) then
          begin
          DrawTreeNode(tree, row, tree.columns[0], node, paint, cRect.left, cRect.top, cRect.right, cRect.bottom);
          end;
        end;
      if cTop > tree.size.cy then
				break;
			cTop := cTop + tree.rowHeight;
      end;
  end;
end;

procedure HideOrShowTreeNode(var tree:FCTree; var node:FCTreeNode; visible:boolean);
var
  childNodesSize:integer;
  i:integer;
begin
  childNodesSize := High(node.childNodes) - Low(node.childNodes) + 1;
  if childNodesSize > 0 then
    begin
    for i := 0 to childNodesSize - 1 do
    begin
      tree.rows[node.childNodes[i].rowIndex].visible := visible;
			HideOrShowTreeNode(tree, node.childNodes[i], visible);
    end;
    end;
end;

procedure CheckOrUnCheckTreeNode(var node:FCTreeNode; checked:boolean);
var
  childNodesSize:integer;
  i:integer;
begin
  if node.checked then
    node.checked := false
  else
    node.checked := true;
  childNodesSize := High(node.childNodes) - Low(node.childNodes) + 1;
  if childNodesSize > 0 then
    begin
    for i := 0 to childNodesSize - 1 do
    begin
			CheckOrUnCheckTreeNode(node.childNodes[i], checked);
    end;
    end;
end;

procedure DrawTreeScrollBar(var tree:FCTree; var paint:FCPaint; clipRect:FCRect);
var
  contentWidth:double;
  contentHeight:double;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
begin
  tree.hScrollIsVisible := false;
  tree.vScrollIsVisible := false;
  if tree.showHScrollBar then
    begin
		contentWidth := GetTreeContentWidth(tree);
		if (contentWidth > 0) and (contentWidth > tree.size.cx) then
      begin
			sLeft := tree.size.cx * tree.scrollH / contentWidth;
			sRight := tree.size.cx * (tree.scrollH + tree.size.cx) / contentWidth;
			if sRight - sLeft < tree.scrollSize then
        begin
				sRight := sLeft + tree.scrollSize;
        end;
			if (touchMoveView.uid = tree.uid) and (tree.hoverScrollHButton or tree.downScrollHButton) then
				paint.FillRect(tree.scrollBarHoveredColor, sLeft, tree.size.cy - tree.scrollSize, sRight, tree.size.cy)
			else
				paint.FillRect(tree.scrollBarColor, sLeft, tree.size.cy - tree.scrollSize, sRight, tree.size.cy);
      tree.hScrollIsVisible := true;
      end;
    end;
	if tree.showVScrollBar then
    begin
		contentHeight := GetTreeContentHeight(tree);
		if (contentHeight > 0) and (contentHeight > tree.size.cy - tree.headerHeight) and (contentHeight > 0) and (tree.size.cy - tree.headerHeight - tree.scrollSize > 0) then
      begin
			sTop := tree.headerHeight + (tree.size.cy - tree.headerHeight - tree.scrollSize) * tree.scrollV / contentHeight;
			sBottom := sTop + (tree.size.cy - tree.headerHeight - tree.scrollSize) * (tree.size.cy - tree.headerHeight - tree.scrollSize) / contentHeight;
			if sBottom - sTop < tree.scrollSize then
        begin
				sBottom := sTop + tree.scrollSize;
        end;
			if (touchMoveView.uid = tree.uid) and (tree.hoverScrollVButton or tree.downScrollVButton) then
				paint.FillRect(tree.scrollBarHoveredColor, tree.size.cx - tree.scrollSize, sTop, tree.size.cx, sBottom)
			else
				paint.FillRect(tree.scrollBarColor, tree.size.cx - tree.scrollSize, sTop, tree.size.cx, sBottom);
      tree.vScrollIsVisible := true;
      end;
    end;
end;

procedure TouchMoveTree(var tree:FCTree; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint);
var
  treeColumn:FCTreeColumn;
  paint:FCPaint;
  mp:FCPoint;
  contentWidth:double;
  subX:double;
  newScrollH:double;
  contentHeight:double;
  subY:double;
  newScrollV:double;
  sLeft:double;
  sRight:double;
  sTop:double;
  sBottom:double;
begin
  paint := tree.GetPaint();
  tree.hoverScrollHButton := false;
	tree.hoverScrollVButton := false;
  mp := firstPoint;
  if firstTouch then
    begin
    if tree.showHScrollBar or tree.showVScrollBar then
      begin
      if tree.downScrollHButton then
        begin
        contentWidth := GetTreeContentWidth(tree);
        subX := contentWidth * (mp.x - tree.startPoint.x) / tree.size.cx;
        newScrollH := tree.startScrollH + subX;
        if newScrollH < 0 then
          newScrollH := 0
        else if newScrollH > contentWidth - tree.size.cx then
          begin
          newScrollH := contentWidth - tree.size.cx;
          end;
        tree.scrollH := newScrollH;
        paint.cancelClick := true;
        end
      else if tree.downScrollVButton then
        begin
        contentHeight := GetTreeContentHeight(tree);
        subY := contentHeight * (mp.y - tree.startPoint.y) / (tree.size.cy - tree.headerHeight - tree.scrollSize);
        newScrollV := tree.startScrollV + subY;
        if newScrollV < 0 then
          newScrollV := 0
        else if newScrollV > contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize) then
          begin
          newScrollV := contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize);
          end;
        tree.scrollV := newScrollV;
        paint.cancelClick := true;
        end;
      end;
    if tree.allowDragScroll then
      begin
      contentWidth := GetTreeContentWidth(tree);
      if contentWidth > tree.size.cx - tree.scrollSize then
        begin
        subX := tree.startPoint.x - mp.x;
        newScrollH := tree.startScrollH + subX;
        if newScrollH < 0 then
          newScrollH := 0
        else if newScrollH > contentWidth - tree.size.cx then
          begin
          newScrollH := contentWidth - tree.size.cx;
          end;
        tree.scrollH := newScrollH;
        if Abs(subX) > 5 then
          begin
          paint.cancelClick := true;
          end;
        end;
      contentHeight := GetTreeContentHeight(tree);
      if contentHeight > tree.size.cy - tree.headerHeight - tree.scrollSize then
        begin
        subY := tree.startPoint.y - mp.y;
        newScrollV := tree.startScrollV + subY;
        if newScrollV < 0 then
          newScrollV := 0
        else if newScrollV > contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize) then
          begin
          newScrollV := contentHeight - (tree.size.cy - tree.headerHeight - tree.scrollSize);
          end;
        tree.scrollV := newScrollV;
        if Abs(subY) > 5 then
          paint.cancelClick := true;
        end;
      end;
    end
  else
		if tree.showHScrollBar then
      begin
			contentWidth := GetTreeContentWidth(tree);
			if (contentWidth > 0) and (contentWidth > tree.size.cx - tree.scrollSize) then
        begin
				sLeft := tree.size.cx * tree.scrollH / contentWidth;
				sRight := tree.size.cx * (tree.scrollH + tree.size.cx) / contentWidth;
				if sRight - sLeft < tree.scrollSize then
          begin
					sRight := sLeft + tree.scrollSize;
          end;
				if (mp.x >= sLeft) and (mp.x <= sRight) and (mp.y >= tree.size.cy - tree.scrollSize) and (mp.y <= tree.size.cy) then
					tree.hoverScrollHButton := true
				else
					tree.hoverScrollHButton := false;
        end;
      end;
		if tree.showVScrollBar then
      begin
			contentHeight := GetTreeContentHeight(tree);
			if (contentHeight > 0) and (contentHeight > tree.size.cy - tree.headerHeight - tree.scrollSize) then
        begin
				sTop := tree.headerHeight + (tree.size.cy - tree.headerHeight - tree.scrollSize) * tree.scrollV / contentHeight;
				sBottom := tree.headerHeight + (tree.size.cy - tree.headerHeight - tree.scrollSize) * (tree.scrollV + (tree.size.cy - tree.headerHeight - tree.scrollSize)) / contentHeight;
				if sBottom - sTop < tree.scrollSize then
          begin
					sBottom := sTop + tree.scrollSize;
          end;
				if (mp.x >= tree.size.cx - tree.scrollSize) and (mp.x <= tree.size.cx) and (mp.y >= sTop) and (mp.y <= sBottom) then
					tree.hoverScrollVButton := true
				else
					tree.hoverScrollVButton := false;
        end;
      end;
end;

procedure TouchDownTree(var tree:FCTree; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
var
  paint:FCPaint;
  mp:FCPoint;
  contentWidth:double;
  sLeft:double;
  sRight:double;
  contentHeight:double;
  sTop:double;
  sBottom:double;
  colLeft:double;
  i:integer;
begin
  paint := tree.GetPaint();
  mp := firstPoint;
	tree.startPoint := mp;
	tree.downScrollHButton := false;
	tree.downScrollVButton := false;
	tree.hoverScrollHButton := false;
	tree.hoverScrollVButton := false;
  if tree.showHScrollBar then
    begin
		contentWidth := GetTreeContentWidth(tree);
		if (contentWidth > 0) and (contentWidth > tree.size.cx - tree.scrollSize) then
      begin
			sLeft := tree.size.cx * tree.scrollH / contentWidth;
			sRight := tree.size.cx * (tree.scrollH + tree.size.cx) / contentWidth;
			if sRight - sLeft < tree.scrollSize then
        begin
				sRight := sLeft + tree.scrollSize;
        end;
			if (mp.x >= sLeft) and (mp.x <= sRight) and (mp.y >= tree.size.cy - tree.scrollSize) and (mp.y <= tree.size.cy) then
        begin
				tree.downScrollHButton := true;
				tree.startScrollH := tree.scrollH;
        end;
      end;
    end;
	if tree.showVScrollBar then
    begin
		contentHeight := GetTreeContentHeight(tree);
		if (contentHeight > 0) and (contentHeight > tree.size.cy - tree.headerHeight - tree.scrollSize) then
      begin
			sTop := tree.headerHeight + (tree.size.cy - tree.headerHeight - tree.scrollSize) * tree.scrollV / contentHeight;
			sBottom := tree.headerHeight + (tree.size.cy - tree.headerHeight - tree.scrollSize) * (tree.scrollV + (tree.size.cy - tree.headerHeight - tree.scrollSize)) / contentHeight;
			if sBottom - sTop < tree.scrollSize then
        begin
				sBottom := sTop + tree.scrollSize;
        end;
			if (mp.x >= tree.size.cx - tree.scrollSize) and (mp.x <= tree.size.cx) and (mp.y >= sTop) and (mp.y <= sBottom) then
        begin
				tree.downScrollVButton := true;
				tree.startScrollV := tree.scrollV;
        end;
      end;
    end;
	if tree.allowDragScroll then
    begin
		tree.startScrollH := tree.scrollH;
		tree.startScrollV := tree.scrollV;
    end;
end;

procedure TouchWheelTree(var tree:FCTree; delta:integer);
var
  oldScrollV:double;
  contentHeight:double;
begin
  oldScrollV := tree.scrollV;
	if delta > 0 then
		oldScrollV := oldScrollV - 10
	else if delta < 0 then
    begin
		oldScrollV := oldScrollV + 10;
    end;
	contentHeight := GetTreeContentHeight(tree);
	if contentHeight < tree.size.cy then
		tree.scrollV := 0
	else
    begin
		if oldScrollV < 0 then
			oldScrollV := 0
		else if oldScrollV > contentHeight - tree.size.cy then
			oldScrollV := contentHeight - tree.size.cy;
		tree.scrollV := oldScrollV;
    end;
end;

procedure UpdateTreeRowIndex(var tree:FCTree);
var
  rowsSize:integer;
  i:integer;
begin
  rowsSize := High(tree.rows) - Low(tree.rows) + 1;
  for i := 0 to rowsSize - 1 do
  begin
    tree.rows[i].rowIndex := i;
    tree.rows[i].cells[0].rowIndex := i;
  end;
end;

function GetTreeLastNodeRowIndex(var node:FCTreeNode):integer;
var
  rowIndex:integer;
  childNodesLength:integer;
  i:integer;
  rIndex:integer;
begin
  rowIndex := node.rowIndex;
  childNodesLength := High(node.childNodes) - Low(node.childNodes) + 1;
  for i := 0 to childNodesLength - 1 do
  begin
    rIndex := GetTreeLastNodeRowIndex(node.childNodes[i]);
		if rowIndex < rIndex then
			rowIndex := rIndex;
  end;
  GetTreeLastNodeRowIndex := rowIndex;
end;

procedure AppendTreeNode(var tree:FCTree; var node:FCTreeNode; var parentNode:FCTreeNode);
var
  newRow:FCTreeRow;
  rowLength:integer;
  childNodeLength:integer;
  newRows:array of FCTreeRow;
  idx:integer;
  i:integer;
begin
  if parentNode.isNotEmpty = false then
    begin
      rowLength := High(tree.rows) - Low(tree.rows) + 1;
      newRow := FCTreeRow.Create();
      SetLength(tree.rows, rowLength + 1);
      tree.rows[rowLength] := newRow;
      SetLength(newRow.cells, 1);
      newRow.cells[0] := node;
      childNodeLength := High(tree.childNodes) - Low(tree.childNodes) + 1;
      SetLength(tree.childNodes, childNodeLength + 1);
      tree.childNodes[childNodeLength] := node;
    end
  else
    begin
      rowLength := High(tree.rows) - Low(tree.rows) + 1;
      newRow := FCTreeRow.Create();
      SetLength(newRows, rowLength + 1);
      childNodeLength := High(parentNode.childNodes) - Low(parentNode.childNodes) + 1;
      if childNodeLength = 0 then
        begin
          idx := parentNode.rowIndex + 1;
          for i := 0 to rowLength do
          begin
            if i < idx then
              newRows[i] := tree.rows[i]
            else if i = idx then
              newRows[i] := newRow
            else 
              newRows[i] := tree.rows[i - 1];
          end;
        end
      else
        begin
          idx := GetTreeLastNodeRowIndex(parentNode) + 1;
          for i := 0 to rowLength do
          begin
            if i < idx then
              newRows[i] := tree.rows[i]
            else if i = idx then
              newRows[i] := newRow
            else 
              newRows[i] := tree.rows[i - 1];
          end;
        end;
      tree.rows := newRows;
      node.SetParentNode(parentNode);
      node.indent := tree.indent;
      node.rowIndex := newRow.rowIndex;
      SetLength(newRow.cells, 1);
      newRow.cells[0] := node;
      SetLength(parentNode.childNodes, childNodeLength + 1);
      parentNode.childNodes[childNodeLength] := node;
      if parentNode.collapsed then
        newRow.visible := false;
    end;
    UpdateTreeRowIndex(tree);
end;

function ToFixed(value:double; digit:integer):string;
var
  formatStr:string;
begin;
  formatStr := '%.' + IntToStr(digit) + 'f';
  ToFixed := Format(formatStr, [value]);
end;

procedure LineXY(var chart:FCChart; x1:double; y1:double; x2:double; y2:double; oX:double; oY:double);
begin
  chart.kChart := 0; 
  chart.bChart := 0;
  if (x1 - oX) <> (x2 - oX) then
    begin
    chart.kChart := ((y2 - oY) - (y1 - oY)) / ((x2 - oX) - (x1 - oX));
    chart.bChart := (y1 - oY) - chart.kChart * (x1 - oX);
    end;
end;

function SelectLine(var chart:FCChart; mp:FCPoint; x1:double; y1:double; x2:double; y2:double):boolean;
var
  res:boolean;
begin
  res := false;
  LineXY(chart, x1, y1, x2, y2, 0, 0);
  if (chart.kChart <> 0) or (chart.bChart <> 0) then
  begin
    if (mp.y / (mp.x * chart.kChart + chart.bChart) > 0.9) and (mp.y / (mp.x * chart.kChart + chart.bChart) <= 1.1) then
      res := true;
  end
  else
  begin
    if (mp.x >= x1 - chart.plotPointSizeChart) and (mp.x <= x1 + chart.plotPointSizeChart) then
      res := true;
  end;
  SelectLine := res;
end;

function SelectRay(var chart:FCChart; mp:FCPoint; x1:double; y1:double; x2:double; y2:double):boolean;
var
  res:boolean;
begin
  res := false;
  LineXY(chart, x1, y1, x2, y2, 0, 0);
  if (chart.kChart <> 0) or (chart.bChart <> 0) then
  begin
    if (mp.y / (mp.x * chart.kChart + chart.bChart) > 0.9) and (mp.y / (mp.x * chart.kChart + chart.bChart) <= 1.1) then
      begin
        if x1 >= x2 then
          begin
          if mp.x > x1 + chart.plotPointSizeChart then
            res := false
          else
            res := true
          end
        else if x1 < x2 then
          begin
          if mp.x < x1 - chart.plotPointSizeChart then
            res := false
          else
            res := true;
          end;
      end;
  end
  else
  begin
    if (mp.x >= x1 - chart.plotPointSizeChart) and (mp.x <= x1 + chart.plotPointSizeChart) then
      begin
      if y1 >= y2 then
        begin
        if mp.y <= y1 - chart.plotPointSizeChart then
          res := true;
        end
      else
       begin
        if mp.y >= y1 - chart.plotPointSizeChart then
          res := true;
        end;
      end;
  end;
  SelectRay := res;
end;

function SelectSegment(var chart:FCChart; mp:FCPoint; x1:double; y1:double; x2:double; y2:double):boolean;
var
  smallX, smallY, bigX, bigY:double;
  res:boolean;
begin
  res := false;
  LineXY(chart, x1, y1, x2, y2, 0, 0);
  if x1 <= x2 then
    smallX := x1
  else
    smallX := x2;
  if y1 <= y2 then
    smallY := y1
  else
    smallY := y2;
  if x1 > x2 then
    bigX := x1
  else
    bigX := x2;
  if y1 > y2 then
    bigY := y1
  else
    bigY := y2;
  if (mp.x >= smallX - 2.0) and (mp.x <= bigX + 2.0) and (mp.y >= smallY - 2.0) and (mp.y <= bigY + 2.0) then
    begin
    if (chart.kChart <> 0) or (chart.bChart <> 0) then
      begin
      if (mp.y / (mp.x * chart.kChart + chart.bChart) > 0.9)and (mp.y / (mp.x * chart.kChart + chart.bChart) <= 1.1) then
        res := true;
      end
    else
      begin
      if (mp.x >= x1 - chart.plotPointSizeChart) and (mp.x <= x1 + chart.plotPointSizeChart) then
        res := true;
      end;
    end;
  SelectSegment := res;
end;

procedure EllipseOR(var chart:FCChart; x1:double; y1:double; x2:double; y2:double; x3:double; y3:double);
begin
  chart.oXChart := ((y3 - y1) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) + (y2 - y1) * (y1 * y1 - y3 * y3 + x1 * x1 - x3 * x3)) / (2 * (x2 - x1) * (y3 - y1) - 2 * (x3 - x1) * (y2 - y1));
  chart.oYChart := ((x3 - x1) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) + (x2 - x1) * (x1 * x1 - x3 * x3 + y1 * y1 - y3 * y3)) / (2 * (y2 - y1) * (x3 - x1) - 2 * (y3 - y1) * (x2 - x1));
  chart.rChart := sqrt((x1 - chart.oXChart) * (x1 - chart.oXChart) + (y1 - chart.oYChart) * (y1 - chart.oYChart));
end;

function EllipseHasPoint(ix:Double; iy:Double; oX:Double; oY:Double; a:Double; b:Double):boolean;
var
  tx, ty:double;
begin
  tx := ix - oX;
  ty := iy - oY;
  if (a = 0) and (b = 0) and (tx = 0) and (ty = 0) then
    EllipseHasPoint := true;
  if a = 0 then
    if (tx = 0) and (ty >= -b) and (ty <= b) then
      EllipseHasPoint := false;
  if b = 0 then
    if (ty = 0) and (tx >= -a) and (tx <= a) then
      EllipseHasPoint := true;
  if ((tx * tx) / (a * a) + (ty * ty) / (b * b) >= 0.8) and ((tx * tx) / (a * a) + (ty * ty) / (b * b) <= 1.2) then
    EllipseHasPoint := true;
  EllipseHasPoint := false;
end;

procedure LinearRegressionEquation(var chart:FCChart; list:DoubleArray);
var
  length:integer;
  sumX:double;
  sumY:double;
  sumUp:double;
  sumDown:double;
  xAvg:double;
  yAvg:double;
  i:integer;
begin
  length := High(list) - Low(list) + 1;
  chart.KChart := 0;
  chart.BChart := 0;
  sumX := 0;
  sumY := 0;
  sumUp := 0;
  sumDown := 0;
  if length > 0 then
    begin
    for i := 0 to length - 1 do
    begin
      sumX := sumX + double(i) + 1.0;
      sumY := sumY + list[i];
    end;
    xAvg := sumX / double(length);
    yAvg := sumY / double(length);
    for i := 0 to length - 1 do
    begin
      sumUp := sumUp + (double(i) + 1.0 - xAvg) * (list[i] - yAvg);
      sumDown := sumDown + (double(i) + 1.0 - xAvg) * (double(i) + 1.0 - xAvg);
    end;
    chart.KChart := sumUp / sumDown;
    chart.BChart := yAvg - chart.KChart * xAvg;
    end;
end;

function MaxValue(list:DoubleArray):double;
var
  res:double;
  i:integer;
  length:integer;
begin
  length := High(list) - Low(list) + 1;
  for i := 0 to length - 1 do
  begin
    if i = 0 then
      res := list[i]
    else
      begin
      if res < list[i] then
        res := list[i];
      end;
  end;
  MaxValue := res;
end;

function MinValue(list:DoubleArray):double;
var
  res:double;
  i:integer;
  length:integer;
begin
  length := High(list) - Low(list) + 1;
  for i := 0 to length - 1 do
  begin
    if i = 0 then
      res := list[i]
    else
      begin
      if res > list[i] then
        res := list[i];
      end;
  end;
  MinValue := res;
end;

function AvgValue(list:DoubleArray):double;
var
  res:double;
  i:integer;
  length:integer;
begin
  res := 0;
  length := High(list) - Low(list) + 1;
  if length > 0 then
    for i := 0 to length - 1 do
    begin
      res := res + list[i];
    end;
  AvgValue := res / length;
end;

procedure Parallelogram(var chart:FCChart; x1:double; y1:double; x2:double; y2:double; x3:double; y3:double);
begin
  chart.x4Chart := x1 + x3 - x2;
  chart.y4Chart := y1 + y3 - y2;
end;

procedure GetPercentParams(y1:double; y2:double; var list:DoubleArray);
var
  y0:double;
	y25:double;
	y50:double;
	y75:double;
	y100:double;
begin
  y0 := 0;
	y25 := 0;
	y50 := 0;
	y75 := 0;
	y100 := 0;
  SetLength(list, 5);
  y0 := y1;
  if y1 <= y2 then
    begin
		y25 := y1 + (y2 - y1) / 4.0;
		y50 := y1 + (y2 - y1) / 2.0;
		y75 := y1 + (y2 - y1) * 3.0 / 4.0;
    end
	else
    begin
		y25 := y2 + (y1 - y2) * 3.0 / 4.0;
		y50 := y2 + (y1 - y2) / 2.0;
		y75 := y2 + (y1 - y2) / 4.0;
    end;
  y100 := y2;
  list[0] := y0;
	list[1] := y25;
	list[2] := y50;
	list[3] := y75;
	list[4] := y100;
end;

function FibonacciValue(idx:integer):integer;
var
  vList:array of integer;
  res:integer;
  i:integer;
begin
  if idx < 1 then
    res := 0
  else if (idx = 1) or (idx = 2) then
    res := 1
  else
  begin
    res := FibonacciValue(idx - 1) + FibonacciValue(idx - 2);
  end;
  FibonacciValue := res;
end;

procedure RectangleXYWH(var chart:FCChart; x1:double; y1:double; x2:double; y2:double);
begin
  if x1 < x2 then
    chart.xChart := x1
  else
    chart.xChart := x2;
  if y1 < y2 then
    chart.yChart := y1
  else
    chart.yChart := y2;
  if x1 - x2 > 0 then
    chart.wChart := x1 - x2
  else
    chart.wChart := x2 - x1;
  if y1 - y2 > 0 then
    chart.hChart := y1 - y2
  else
    chart.hChart := y2 - y1;
  if chart.wChart <= 0 then
    chart.wChart := 4;
  if chart.hChart <= 0 then
    chart.hChart := 4;
end;

function GetEMA(n:integer; value:double; lastEMA:double):double;
begin
  GetEMA := (value * 2 + lastEMA * double(n - 1)) / double(n + 1);
end;

procedure GetMACD(dif:DoubleArray; dea:DoubleArray; var macd:DoubleArray);
var
  length:integer;
  i:integer;
begin
  length := High(dif) - Low(dif) + 1;
  for i := 0 to length - 1 do
  begin
    macd[i] := (dif[i] - dea[i]) * 2;
  end;
end;

procedure GetDIF(close12:DoubleArray; close26:DoubleArray; var dif:DoubleArray);
var
  length:integer;
  i:integer;
begin
  length := High(close12) - Low(close12) + 1;
  for i := 0 to length - 1 do
  begin
    dif[i] := close12[i] - close26[i];
  end;
end;

procedure MaValue(ticks:DoubleArray; days:integer; var mas:DoubleArray);
var
  last, ma, maSum: double;
	length: integer;
  i: integer;
begin
  last := 0;
  ma := 0;
  maSum := 0;
  length := High(ticks) - Low(ticks) + 1;
  SetLength(mas, length);
  for i := 0 to length - 1 do
    begin
    ma := 0;
    if i >= days then
      begin
			last := ticks[i - days];
			maSum := maSum + ticks[i] - last;
			ma := maSum / double(days);
      end
    else
      begin
      maSum := maSum + ticks[i];
			ma := maSum / double(i + 1);
      end;
		mas[i] := ma;
    end;
end;

procedure HHVValue(ticks:DoubleArray; days:integer; var hhv:DoubleArray);
var
  maxValue: double;
	length: integer;
  i: integer;
  j: integer;
begin
  j := 0;
  maxValue := ticks[0];
  length := High(ticks) - Low(ticks) + 1;
  for i := 0 to length - 1 do
    begin
      if i >= days then
        begin
        maxValue := ticks[i];
        j := i;
        while j > i - days do
        begin
          if maxValue < ticks[j] then
            begin
            maxValue := ticks[j];
            end;
          j := j - 1;
				end;
        hhv[i] := maxValue;
        end
			else
        begin
        if maxValue < ticks[i] then
          begin
				  maxValue := ticks[i];
          end;
			  hhv[i] := maxValue;
        end;
    end;
end;

procedure LLVValue(ticks:DoubleArray; days:integer; var llv:DoubleArray);
var
  minValue: double;
	length: integer;
  i: integer;
  j: integer;
begin
  j := 0;
  minValue := ticks[0];
  length := High(ticks) - Low(ticks) + 1;
  for i := 0 to length - 1 do
    begin
      if i >= days then
        begin
        minValue := ticks[i];
        j := i;
        while j > i - days  do
        begin
          if minValue > ticks[j] then
            begin
            minValue := ticks[j];
            end;
          j := j - 1;
			  end;
        llv[i] := minValue;
        end
			else
        begin
        if minValue > ticks[i] then
          begin
				  minValue := ticks[i];
          end;
			  llv[i] := minValue;
        end;
    end;
end;

procedure RefValue(ticks:DoubleArray; days:integer; var refArr:DoubleArray);
var
	length: integer;
  i: integer;
  refValue: double;
begin
  length := High(ticks) - Low(ticks) + 1;
  for i := 0 to length - 1 do
    begin
      refValue := 0;
      if i >= days then
			  refValue := ticks[i - days]
		  else 
        begin
			  RefValue := ticks[1];
        end;
      refArr[i] := refValue;
    end;
end;

procedure GetTRIXData(ticks:DoubleArray; n:integer; m:integer; var trixArr:DoubleArray; var matrixArr:DoubleArray);
var
  emaArr1:DoubleArray;
  emaArr2:DoubleArray;
  ref:DoubleArray;
  mtrArr:DoubleArray;
  length: integer;
  i:integer;
begin
  length := High(ticks) - Low(ticks) + 1;
  SetLength(emaArr1, length);
  SetLength(emaArr2, length);
  SetLength(ref, length);
  SetLength(mtrArr, length);
  SetLength(trixArr, length);
  SetLength(matrixArr, length);
  emaArr1[0] := ticks[0];
  for i := 1 to length - 1 do
  begin
    emaArr1[i] := GetEMA(n, ticks[i], emaArr1[i - 1]);
  end;
  emaArr2[0] := emaArr1[0];
  for i := 1 to length - 1 do
  begin
    emaArr2[i] := GetEMA(n, emaArr1[i], emaArr2[i - 1]);
  end;
  mtrArr[0] := emaArr2[0];
  for i := 1 to length - 1 do
  begin
    mtrArr[i] := GetEMA(n, emaArr2[i], mtrArr[i - 1]);
  end;
  RefValue(mtrArr, 1, ref);
  for i := 0 to length - 1 do
  begin
    trixArr[i] := 100.0 * (mtrArr[i] - ref[i]) / ref[i];
  end;
  MaValue(trixArr, length, matrixArr);
end;

function StandardDeviationSum(listValue:DoubleArray; avgValue:double):double;
var
  i:integer;
  length:integer;
  targetValue:double;
  sumValue:double;
begin
  length := High(listValue) - Low(listValue) + 1;
  targetValue := listValue[length - 1];
  sumValue := (targetValue - avgValue) * (targetValue - avgValue);
  for i := 0 to length - 2 do
  begin
    sumValue := sumValue + (listValue[i] - avgValue) * (listValue[i] - avgValue);
  end;
  StandardDeviationSum := sumValue;
end;

procedure GetBollData(ticks:DoubleArray; maDays:integer; var ups:DoubleArray; var mas:DoubleArray; var lows:DoubleArray);
var
  tickBegin:integer;
  maSum:double;
  mdSum:double;
  p:double;
  c:double;
  ma:double;
  md:double;
  bstart:integer;
  i, j:integer;
  length:integer;
  pos:integer;
  values:DoubleArray;
begin
  length := High(ticks) - Low(ticks) + 1;
  tickBegin := maDays;
  maSum := 0;
  mdSum := 0;
  p := 0;
  ma := 0;
  md := 0;
  c := 0;
  bstart := 0;
  pos := 0;
  j := 0;
  SetLength(ups, length);
  SetLength(mas, length);
  SetLength(lows, length);
  SetLength(values, length);
  for i := 0 to length - 1 do
  begin
    c := ticks[i];
    ma := 0.0;
    md := 0.0;
    bstart := 0;
    mdSum := 0.0;
    maSum := maSum + c;
    if i >= tickBegin then
      begin
      maSum := maSum - p;
			ma := maSum / double(maDays);
			bstart := i - tickBegin;
			p := ticks[bstart];
      mas[i] := ma;
      bstart := i - tickBegin;
			p := ticks[bstart];
      pos := 0;
      for j := bstart to bstart + maDays - 1 do
      begin
        values[pos] := ticks[j];
        pos := pos + 1;
      end;
      SetLength(values, pos);
      mdSum := StandardDeviationSum(values, ma);
      md := Sqrt(mdSum / double(maDays));
			ups[i] := ma + 2.0 * md;
			lows[i] := ma - 2.0 * md;
      end
    else
      begin
      ma := maSum / double(i + 1);
			mas[i] := ma;
      pos := 0;
      for j := 0 to i do
      begin
        values[pos] := ticks[j];
        pos := pos + 1;
      end;
      SetLength(values, pos);
      mdSum := StandardDeviationSum(values, ma);
      md := Sqrt(mdSum / double(maDays));
			ups[i] := ma + 2.0 * md;
			lows[i] := ma - 2.0 * md;
      end
  end;
end;

procedure GetKDJData(highArr:DoubleArray;lowArr:DoubleArray; closeArr:DoubleArray; n:integer; m1:integer; m2:integer; var ks:DoubleArray; var ds:DoubleArray; var js:DoubleArray);
var
  days:integer;
  lastK:double;
  lastD:double;
  curK:double;
  curD:double;
  i, j, m:integer;
  length:integer;
  rsvs:DoubleArray;
  highList:DoubleArray;
  lowList:DoubleArray;
  startIndex:integer;
  close:double;
  maxHigh:double;
  minLow:double;
  length2:integer;
  pos:integer;
  highValue,lowValue:double;
begin
  days := n;
  length := High(highArr) - Low(highArr) + 1;
  SetLength(ks, length);
  SetLength(ds, length);
  SetLength(js, length);
  SetLength(rsvs, length);
  SetLength(highList, length);
  SetLength(lowList, length);
  lastK := 0;
  lastD := 0;
  curK := 0;
  curD := 0;
  close := 0;
  maxHigh := 0;
  minLow := 0;
  startIndex := 0;
  length2 := 0;
  i := 0;
  j := 0;
  m := 0;
  pos := 0;
  highValue := 0;
  lowValue := 0;
  for i := 0 to length - 1 do
  begin
    startIndex := i - days;
    if startIndex < 0 then
      startIndex := 0;
    pos := 0;
    for j := startIndex to i do
    begin
      highList[pos] := highArr[j];
      lowList[pos] := lowArr[j];
      pos := pos + 1;
    end;
    close := closeArr[i];
    maxHigh := 0.0;
    minLow := 0.0;
    for m := 0 to i - startIndex do
    begin
      highValue := highList[m];
      lowValue := lowList[m];
      if highValue > maxHigh then
          maxHigh := highValue;
      if lowValue < minLow then
          minLow := lowValue;
    end;
    if maxHigh = minLow then
			rsvs[i] := 0.0
		else
			rsvs[i] := (close - minLow) / (maxHigh - minLow) * 100.0;
    if i = 0 then
      begin
			lastK := rsvs[i];
      lastD := rsvs[i];
      end;
    curK := double(m1 - 1.0) / double(m1) * lastK + 1.0 / double(m1) * rsvs[i];
		ks[i] := curK;
		lastK := curK;
		curD := double(m2 - 1.0) / double(m2) * lastD + 1.0 / double(m2) * curK;
		ds[i] := curD;
		lastD := curD;
    js[i] := 3.0 * curK - 2.0 * curD;
  end;
end;

procedure GetRSIData(ticks:DoubleArray; n1:integer; n2:integer; n3:integer; var rsi1:DoubleArray; var rsi2:DoubleArray; var rsi3:DoubleArray);
var
  length: integer;
  i:integer;
  lastClosePx, lastSm1, lastSa1, lastSm2, lastSa2, lastSm3, lastSa3:double;
  c, m, a:double;
begin
  length := High(ticks) - Low(ticks) + 1;
  lastClosePx := ticks[0];
  lastSm1 :=  0.0;
  lastSa1 := 0.0;
  lastSm2 := 0.0;
  lastSa2 := 0.0;
  lastSm3 := 0.0;
  lastSa3 := 0.0;
  c := 0;
  m := 0;
  a := 0;
  SetLength(rsi1, length);
  SetLength(rsi2, length);
  SetLength(rsi3, length);
  for i := 0 to length - 1 do
  begin
    c := ticks[i];
    if c - lastClosePx > 0 then
      m := c - lastClosePx
    else
      m := 0;
    if c - lastClosePx > 0 then
      a := c - lastClosePx
    else
      a := lastClosePx - c;
    if i = 0 then
      begin
      lastSm1 := 0.0;
      lastSa1 := 0.0;
      rsi1[i] := 0;
      end
    else
      begin
      lastSm1 := (m + (double(n1 - 1)) * lastSm1) / double(n1);
		  lastSa1 := (a + (double(n1 - 1)) * lastSa1)/ double(n1);
      if lastSa1 <> 0.0 then
        rsi1[i] := 100.0 * lastSm1 / lastSa1
      else
        rsi1[i] := 0;
      end;
    if i = 0 then
      begin
      lastSm2 := 0.0;
      lastSa2 := 0.0;
      rsi2[i] := 0;
      end
    else
      begin
      lastSm2 := (m + (double(n2 - 1)) * lastSm2) / double(n2);
		  lastSa2 := (a + (double(n2 - 1)) * lastSa2)/ double(n2);
      if lastSa2 <> 0.0 then
        rsi2[i] := 100.0 * lastSm2 / lastSa2
      else
        rsi2[i] := 0;
      end;
    if i = 0 then
      begin
      lastSm3 := 0.0;
      lastSa3 := 0.0;
      rsi3[i] := 0;
      end
    else
      begin
      lastSm3 := (m + (double(n3 - 1)) * lastSm3) / double(n3);
		  lastSa3 := (a + (double(n3 - 1)) * lastSa3)/ double(n3);
      if lastSa3 <> 0.0 then
        rsi3[i] := 100 * lastSm3 / lastSa3
      else
        rsi3[i] := 0;
      end;
    lastClosePx := c;
  end;
end;

procedure GetRocData(ticks:DoubleArray; n:integer; m:integer; var roc:DoubleArray; var maroc:DoubleArray);
var
  length: integer;
  i:integer;
  currRoc:double;
begin
  length := High(ticks) - Low(ticks) + 1;
  SetLength(roc, length);
  SetLength(maroc, length);
  currRoc := 0;
  for i := 0 to length - 1 do
  begin
    currRoc := 0.0;
    if i >= n then
      begin
      currRoc := 100.0 * (ticks[i] - ticks[i - n]) / ticks[i - n];
      roc[i] := currRoc;
      end
    else
      begin
      currRoc := 100.0 * (ticks[i] - ticks[0]) / ticks[0];
      roc[i] := currRoc;
      end
  end;
  MaValue(roc, m, maroc);
end;

procedure GetBIASData(ticks:DoubleArray; n1:integer; n2:integer; n3:integer; var bias1Arr:DoubleArray; var bias2Arr:DoubleArray; var bias3Arr:DoubleArray);
var
  ma1:DoubleArray;
  ma2:DoubleArray;
  ma3:DoubleArray;
  length: integer;
  i:integer;
begin
  length := High(ticks) - Low(ticks) + 1;
  SetLength(ma1, length);
  SetLength(ma2, length);
  SetLength(ma3, length);
  SetLength(bias1Arr, length);
  SetLength(bias2Arr, length);
  SetLength(bias3Arr, length);
  MaValue(ticks, n1, ma1);
	MaValue(ticks, n2, ma2);
	MaValue(ticks, n3, ma3);
  for i := 0 to length - 1 do
  begin
    bias1Arr[i] := (ticks[i] - ma1[i]) / ma1[i] * 100.0;
    bias2Arr[i] := (ticks[i] - ma2[i]) / ma2[i] * 100.0;
    bias3Arr[i] := (ticks[i] - ma2[i]) / ma3[i] * 100.0;
  end;
end;

procedure GetBBIData(ticks:DoubleArray; n1:integer; n2:integer; n3:integer; n4:integer; var bbiArr:DoubleArray);
var
  ma3:DoubleArray;
  ma6:DoubleArray;
  ma12:DoubleArray;
  ma24:DoubleArray;
  length: integer;
  i:integer;
begin
  length := High(ticks) - Low(ticks) + 1;
  SetLength(ma3, length);
  SetLength(ma6, length);
  SetLength(ma12, length);
  SetLength(ma24, length);
  SetLength(bbiArr, length);
  MaValue(ticks, n1, ma3);
	MaValue(ticks, n2, ma6);
	MaValue(ticks, n3, ma12);
  MaValue(ticks, n4, ma24);
  for i := 0 to length - 1 do
  begin
    bbiArr[i] := (ma3[i] + ma6[i] + ma12[i] + ma24[i]) / 4.0;
  end;
end; 

procedure GetWRData(closeArr:DoubleArray; highArr:DoubleArray; lowArr:DoubleArray; n1:integer; n2:integer; var wr1Arr:DoubleArray; var wr2Arr:DoubleArray);
var
  highArr1:DoubleArray;
  highArr2:DoubleArray;
  lowArr1:DoubleArray;
  lowArr2:DoubleArray;
  length: integer;
  i:integer;
  high1:double;
  low1:double;
  high2:double;
  low2:double;
  close:double;
begin
  length := High(highArr) - Low(highArr) + 1;
  SetLength(wr1Arr, length);
  SetLength(wr2Arr, length);
  SetLength(highArr1, length);
  SetLength(highArr2, length);
  SetLength(lowArr1, length);
  SetLength(lowArr2, length);
  HHVValue(highArr, n1, highArr1);
	HHVValue(highArr, n2, highArr2);
	LLVValue(lowArr, n1, lowArr1);
	LLVValue(lowArr, n2, lowArr2);
  for i := 0 to length - 1 do
  begin
    high1 := highArr1[i];
		low1 := lowArr1[i];
		high2 := highArr2[i];
		low2 := lowArr2[i];
		close := closeArr[i];
    wr1Arr[i] := 100 * (high1 - close) / (high1 - low1);
		wr2Arr[i] := 100 * (high2 - close) / (high2 - low2);
  end;
end; 

procedure GetDMAData(ticks:DoubleArray; n1:integer; n2:integer; var difArr:DoubleArray; var difmaArr:DoubleArray);
var
  ma10:DoubleArray;
  ma50:DoubleArray;
  length: integer;
  i:integer;
begin
  length := High(ticks) - Low(ticks) + 1;
  SetLength(ma10, length);
  SetLength(ma50, length);
  SetLength(difArr, length);
  SetLength(difmaArr, length);
  MaValue(ticks, n1, ma10);
	MaValue(ticks, n2, ma50);
  for i := 0 to length - 1 do
  begin
    difArr[i] := ma10[i] - ma50[i];
  end;
  MaValue(difArr, length, difmaArr);
end; 

procedure GetCCIData(highArr:DoubleArray; lowArr:DoubleArray; closeArr:DoubleArray; n:integer; var cciArr:DoubleArray);
var
  tpArr:DoubleArray;
  maClose:DoubleArray;
  mdArr:DoubleArray;
  maMD:DoubleArray;
  length: integer;
  i:integer;
begin
  length := High(highArr) - Low(highArr) + 1;
  SetLength(tpArr, length);
  SetLength(maClose, length);
  SetLength(mdArr, length);
  SetLength(maMD, length);
  SetLength(cciArr, length);
  for i := 0 to length - 1 do
  begin
    tpArr[i] := (highArr[i] + lowArr[i] + closeArr[i]) / 3.0;
  end;
  MaValue(closeArr, n, maClose);
  for i := 0 to length - 1 do
  begin
    mdArr[i] := maClose[i] - closeArr[i];
  end;
  MaValue(mdArr, n, maMD);
  for i := 0 to length - 1 do
  begin
    if maMD[i] > 0 then
      cciArr[i] := (tpArr[i] - maClose[i]) / (maMD[i] * 0.015)
    else
      cciArr[i] := 0;
  end;
end; 

procedure CalculateChartMaxMin(var chart:FCChart);
var
  isTrend:boolean;
  firstOpen:double;
  load1:boolean;
	load2:boolean;
	load3:boolean;
	load4:boolean;
  length: integer;
  lastValidIndex:integer;
  i:integer;
  shapeLength:integer;
  shape:BaseShape;
  j:integer;
  k:integer;
  shapeDatasLength:integer;
  shapeDatas2Length:integer;
  subMax:double;
begin
  chart.candleMax := 0;
	chart.candleMin := 0;
	chart.volMax := 0;
	chart.volMin := 0;
	chart.indMin := 0;
	chart.indMin := 0;
  load1 := false;
	load2 := false;
	load3 := false;
	load4 := false;
  lastValidIndex := 0;
  i := 0;
  j := 0;
  k := 0;
  shapeDatasLength := 0;
  shapeDatas2Length := 0;
  subMax := 0;
  length := High(chart.data) - Low(chart.data) + 1;
  shapeLength := High(chart.shapes) - Low(chart.shapes) + 1;
  isTrend := false;
  if chart.cycle = 'trend' then
    isTrend := true;
  firstOpen := chart.firstOpen;
  if length > 0 then
    begin
    lastValidIndex := chart.lastVisibleIndex;
		if chart.lastValidIndex <> -1 then
			lastValidIndex := chart.lastValidIndex;
    for i := chart.firstVisibleIndex to lastValidIndex do
    begin
      if i = chart.firstVisibleIndex then
        begin
        if isTrend then
          begin
					chart.candleMax := chart.data[i].close;
					chart.candleMin := chart.data[i].close;
          if firstOpen = 0 then
					  firstOpen := chart.data[i].close;
          end
				else
          begin
					chart.candleMax := chart.data[i].high;
					chart.candleMin := chart.data[i].low;
          end;
        load1 := true;
				load2 := true;
				chart.volMax := chart.data[i].volume;
        if chart.showIndicator = 'MACD' then
          begin
					chart.indMax := chart.alldifarr[i];
					chart.indMin := chart.alldifarr[i];
					load3 := true;
          end
				else if chart.showIndicator = 'KDJ' then
          begin
					chart.indMax := chart.kdjK[i];
					chart.indMin := chart.kdjK[i];
					load3 := true;
          end
				else if chart.showIndicator = 'RSI' then
          begin
					chart.indMax := chart.rsi1[i];
					chart.indMin := chart.rsi1[i];
					load3 := true;
          end
				else if chart.showIndicator = 'BIAS' then
          begin
					chart.indMax := chart.bias1[i];
					chart.indMin := chart.bias1[i];
					load3 := true;
          end
				else if chart.showIndicator = 'ROC' then
          begin
					chart.indMax := chart.roc[i];
					chart.indMin := chart.roc[i];
					load3 := true;
          end
				else if chart.showIndicator = 'WR' then
          begin
					chart.indMax := chart.wr1[i];
					chart.indMin := chart.wr1[i];
					load3 := true;
          end
				else if chart.showIndicator = 'CCI' then
          begin
					chart.indMax := chart.cci[i];
					chart.indMin := chart.cci[i];
					load3 := true;
          end
				else if chart.showIndicator = 'BBI' then
          begin
					chart.indMax := chart.bbi[i];
					chart.indMin := chart.bbi[i];
					load3 := true;
          end
				else if chart.showIndicator = 'TRIX' then
          begin
					chart.indMax := chart.trix[i];
					chart.indMin := chart.trix[i];
					load3 := true;
          end
				else if chart.showIndicator = 'DMA' then
          begin
					chart.indMax := chart.dma1[i];
					chart.indMin := chart.dma1[i];
					load3 := true;
          end;
        end
      else
        begin
        if isTrend then
          begin
					if chart.candleMax < chart.data[i].close then
						chart.candleMax := chart.data[i].close;
					if chart.candleMin > chart.data[i].close then
						chart.candleMin := chart.data[i].close;
          end
				else
          begin
					if chart.candleMax < chart.data[i].high then
						chart.candleMax := chart.data[i].high;
					if chart.candleMin > chart.data[i].low then
						chart.candleMin := chart.data[i].low;
          end;
        if chart.volMax < chart.data[i].volume then
          chart.volMax := chart.data[i].volume;
        if chart.showIndicator = 'MACD' then
          begin
          if chart.indMax < chart.alldifarr[i] then
            chart.indMax := chart.alldifarr[i];
          if chart.indMax < chart.alldeaarr[i] then
            chart.indMax := chart.alldeaarr[i];
          if chart.indMax < chart.allmacdarr[i] then
            chart.indMax := chart.allmacdarr[i];
          if chart.indMin > chart.alldifarr[i] then
            chart.indMin := chart.alldifarr[i];
          if chart.indMin > chart.alldeaarr[i] then
            chart.indMin := chart.alldeaarr[i];
          if chart.indMin > chart.allmacdarr[i] then
            chart.indMin := chart.allmacdarr[i];
          end
        else if chart.showIndicator = 'KDJ' then
          begin
          if chart.indMax < chart.kdjK[i] then
            chart.indMax := chart.kdjK[i];
          if chart.indMax < chart.kdjD[i] then
            chart.indMax := chart.kdjD[i];
          if chart.indMax < chart.kdjJ[i] then
            chart.indMax := chart.kdjJ[i];
          if chart.indMin > chart.kdjK[i] then
            chart.indMin := chart.kdjK[i];
          if chart.indMin > chart.kdjD[i] then
            chart.indMin := chart.kdjD[i];
          if chart.indMin > chart.kdjJ[i] then
            chart.indMin := chart.kdjJ[i];
          end
        else if chart.showIndicator = 'RSI' then
          begin
          if chart.indMax < chart.rsi1[i] then
            chart.indMax := chart.rsi1[i];
          if chart.indMax < chart.rsi2[i] then
            chart.indMax := chart.rsi2[i];
          if chart.indMax < chart.rsi3[i] then
            chart.indMax := chart.rsi3[i];
          if chart.indMin > chart.rsi1[i] then
            chart.indMin := chart.rsi1[i];
          if chart.indMin > chart.rsi2[i] then
            chart.indMin := chart.rsi2[i];
          if chart.indMin > chart.rsi3[i] then
            chart.indMin := chart.rsi3[i];
          end
        else if chart.showIndicator = 'BIAS' then
          begin
          if chart.indMax < chart.bias1[i] then
            chart.indMax := chart.bias1[i];
          if chart.indMax < chart.bias2[i] then
            chart.indMax := chart.bias2[i];
          if chart.indMax < chart.bias3[i] then
            chart.indMax := chart.bias3[i];
          if chart.indMin > chart.bias1[i] then
            chart.indMin := chart.bias1[i];
          if chart.indMin > chart.bias2[i] then
            chart.indMin := chart.bias2[i];
          if chart.indMin > chart.bias3[i] then
            chart.indMin := chart.bias3[i];
          end
        else if chart.showIndicator = 'ROC' then
          begin
          if chart.indMax < chart.roc[i] then
            chart.indMax := chart.roc[i];
          if chart.indMax < chart.rocMa[i] then
            chart.indMax := chart.rocMa[i];
          if chart.indMin > chart.roc[i] then
            chart.indMin := chart.roc[i];
          if chart.indMin > chart.rocMa[i] then
            chart.indMin := chart.rocMa[i];
          end
        else if chart.showIndicator = 'WR' then
          begin
          if chart.indMax < chart.wr1[i] then
            chart.indMax := chart.wr1[i];
          if chart.indMax < chart.wr2[i] then
            chart.indMax := chart.wr2[i];
          if chart.indMin > chart.wr1[i] then
            chart.indMin := chart.wr1[i];
          if chart.indMin > chart.wr2[i] then
            chart.indMin := chart.wr2[i];
          end
        else if chart.showIndicator = 'CCI' then
          begin
          if chart.indMax < chart.cci[i] then
            chart.indMax := chart.cci[i];
          if chart.indMin > chart.cci[i] then
            chart.indMin := chart.cci[i];
          end
        else if chart.showIndicator = 'BBI' then
          begin
          if chart.indMax < chart.bbi[i] then
            chart.indMax := chart.bbi[i];
          if chart.indMin > chart.bbi[i] then
            chart.indMin := chart.bbi[i];
          end
        else if chart.showIndicator = 'TRIX' then
          begin
          if chart.indMax < chart.trix[i] then
            chart.indMax := chart.trix[i];
          if chart.indMax < chart.trixMa[i] then
            chart.indMax := chart.trixMa[i];
          if chart.indMin > chart.trix[i] then
            chart.indMin := chart.trix[i];
          if chart.indMin > chart.trixMa[i] then
            chart.indMin := chart.trixMa[i];
          end
        else if chart.showIndicator = 'DMA' then
          begin
          if chart.indMax < chart.dma1[i] then
            chart.indMax := chart.dma1[i];
          if chart.indMax < chart.dma2[i] then
            chart.indMax := chart.dma2[i];
          if chart.indMin > chart.dma1[i] then
            chart.indMin := chart.dma1[i];
          if chart.indMin > chart.dma2[i] then
            chart.indMin := chart.dma2[i];
          end;
        end;
    end;
    end; 
  if shapeLength > 0 then
    begin
    lastValidIndex := chart.lastVisibleIndex;
    if chart.lastValidIndex <> -1 then
      lastValidIndex := chart.lastValidIndex;
    for j := 0 to shapeLength - 1 do
    begin
      shape := chart.shapes[i];   
      shapeLength := High(shape.datas) - Low(shape.datas) + 1;
      if shapeLength > 0 then
        begin
        for k := chart.firstVisibleIndex to lastValidIndex do
          if shape.divIndex = 0 then
            begin
            if (load1 = false) and (i = chart.firstVisibleIndex) then
              begin
              if shape.leftOrRight then
                begin
                chart.candleMax := shape.datas[i];
                chart.candleMin := shape.datas[i];
                end
              else
                begin
                chart.candleMaxRight := shape.datas[i];
                chart.candleMinRight := shape.datas[i];
                end;
              load1 := true;
              end
            else
              begin
              if shape.leftOrRight then
                begin
                if shape.datas[i] > chart.candleMax then
                  chart.candleMax := shape.datas[i];
                if shape.datas[i] < chart.candleMin then
                  chart.candleMin := shape.datas[i];
                end
              else
                begin
                if shape.datas[i] > chart.candleMaxRight then
                  chart.candleMaxRight := shape.datas[i];
                if shape.datas[i] < chart.candleMinRight then
                  chart.candleMinRight := shape.datas[i];
                end;
              end;
            end
          else if shape.divIndex = 1 then
            begin
            if (load2 = false) and (i = chart.firstVisibleIndex) then
              begin
              if shape.leftOrRight then
                begin
                chart.volMax := shape.datas[i];
                chart.volMin := shape.datas[i];
                end
              else
                begin
                chart.volMax := shape.datas[i];
                chart.volMin := shape.datas[i];
                end;
              load2 := true;
              end
            else
              begin
              if shape.leftOrRight then
                begin
                if shape.datas[i] > chart.volMax then
                  chart.volMax := shape.datas[i];
                if shape.datas[i] < chart.volMin then
                  chart.volMin := shape.datas[i];
                end
              else
                begin
                if shape.datas[i] > chart.volMax then
                  chart.volMax := shape.datas[i];
                if shape.datas[i] < chart.volMin then
                  chart.volMin := shape.datas[i];
                end;
              end;
            end
          else if shape.divIndex = 2 then
            begin
            if (load3 = false) and (i = chart.firstVisibleIndex) then
              begin
              if shape.leftOrRight then
                begin
                chart.indMax := shape.datas[i];
                chart.indMin := shape.datas[i];
                end
              else
                begin
                chart.indMax := shape.datas[i];
                chart.indMin := shape.datas[i];
                end;
              load3 := true;
              end
            else
              begin
              if shape.leftOrRight then
                begin
                if shape.datas[i] > chart.indMax then
                  chart.indMax := shape.datas[i];
                if shape.datas[i] < chart.indMin then
                  chart.indMin := shape.datas[i];
                end
              else
                begin
                if shape.datas[i] > chart.indMax then
                  chart.indMax := shape.datas[i];
                if shape.datas[i] < chart.indMin then
                  chart.indMin := shape.datas[i];
                end;
              end;
            end;
      shapeDatas2Length := High(shape.datas2) - Low(shape.datas2) + 1;
      if shapeDatas2Length > 0 then
        for k := chart.firstVisibleIndex to lastValidIndex do
          begin
          if shape.divIndex = 0 then
            begin
            if shape.leftOrRight then
              begin
              if shape.datas2[i] > chart.candleMax then
                chart.candleMax := shape.datas2[i];
              if shape.datas2[i] < chart.candleMin then
                chart.candleMin := shape.datas2[i];
              end
            else
              begin
              if shape.datas2[i] > chart.candleMaxRight then
                chart.candleMaxRight := shape.datas2[i];
              if shape.datas2[i] < chart.candleMinRight then
                chart.candleMinRight := shape.datas2[i];
              end;
            end
          else if shape.divIndex = 1 then
            begin
            if shape.leftOrRight then
              begin
              if shape.datas2[i] > chart.volMax then
                chart.volMax := shape.datas2[i];
              if shape.datas2[i] < chart.volMin then
                chart.volMin := shape.datas2[i];
              end
            else
              begin
              if shape.datas2[i] > chart.volMax then
                chart.volMax := shape.datas2[i];
              if shape.datas2[i] < chart.volMin then
                chart.volMin := shape.datas2[i];
              end;
            end
          else if shape.divIndex = 2 then
            begin
            if shape.leftOrRight then
              begin
              if shape.datas2[i] > chart.indMax then
                chart.indMax := shape.datas2[i];
              if shape.datas2[i] < chart.indMin then
                chart.indMin := shape.datas2[i];
              end
            else
              begin
              if shape.datas2[i] > chart.indMax then
                chart.indMax := shape.datas2[i];
              if shape.datas2[i] < chart.indMin then
                chart.indMin := shape.datas2[i];
              end;
            end;
          end;
        end;
      end;
    end;  
  if isTrend then
    begin
    if chart.candleMax - firstOpen > chart.candleMin - firstOpen then
      subMax := chart.candleMax - firstOpen
    else
      subMax := chart.candleMin - firstOpen;
    chart.candleMax := firstOpen + subMax;
    chart.candleMin := firstOpen - subMax;
    end
  else
    begin
    if (chart.candleMax = 0) and (chart.candleMin = 0) then
      begin
      chart.candleMax := 1;
      chart.candleMin := -1;
      end;
    if (chart.volMax = 0) and (chart.volMin = 0) then
      begin
      chart.volMax := 1;
      chart.volMin := -1;
      end;
    if (chart.indMax = 0) and (chart.indMin = 0) then
      begin
      chart.indMax := 1;
      chart.indMin := -1;
      end;
    if (chart.candleMaxRight = 0) and (chart.candleMinRight = 0) then
      begin
      chart.candleMaxRight := 1;
      chart.candleMinRight := -1;
      end;
    if (chart.volMaxRight = 0) and (chart.volMinRight = 0) then
      begin
      chart.volMaxRight := 1;
      chart.volMinRight := -1;
      end;
    if (chart.indMaxRight = 0) and (chart.indMinRight = 0) then
      begin
      chart.indMaxRight := 1;
      chart.indMinRight := -1;
      end;
    end;
end;

function GetChartIndex(var chart:FCChart; mp:FCPoint):integer;
var
  length:integer;
  idx:integer;
  intX:integer;
begin
  length := High(chart.data) - Low(chart.data) + 1;
  if length = 0 then
      GetChartIndex := -1;
  if mp.x <= 0 then
      GetChartIndex := 0;
  intX := trunc(mp.x - chart.leftVScaleWidth - chart.hScalePixel - chart.offsetX);
  if intX < 0 then
    intX := 0;
  idx := chart.firstVisibleIndex + trunc(double(intX) / chart.hScalePixel);
  if chart.hScalePixel > 1 then
    begin
    if intX mod trunc(chart.hScalePixel) <> 0 then
      idx := idx + 1;
    end;
  if idx < 0 then
      idx := 0
  else if idx > length - 1 then
      idx := length - 1;
  GetChartIndex := idx;
end;

function GetChartMaxVisibleCount(var chart:FCChart; hScalePixel:double; pureH:double):integer;
var
  count:integer;
begin
  count := trunc(pureH / hScalePixel);
  if count < 0 then
    count := 0;
  GetChartMaxVisibleCount := count;
end;

function GetCandleDivHeight(var chart:FCChart):double;
var
  height:double;
begin
  height := chart.size.cy - chart.hScaleHeight;
  if height > 0 then
    GetCandleDivHeight := height * chart.candleDivPercent
  else
    GetCandleDivHeight := 0;
end;

function GetVolDivHeight(var chart:FCChart):double;
var
  height:double;
begin
  height := chart.size.cy - chart.hScaleHeight;
  if height > 0 then
    GetVolDivHeight := height * chart.volDivPercent
  else
    GetVolDivHeight := 0;
end;

function GetIndDivHeight(var chart:FCChart):double;
var
  height:double;
begin
  height := chart.size.cy - chart.hScaleHeight;
  if height > 0 then
    GetIndDivHeight := height * chart.indDivPercent
  else
    GetIndDivHeight := 0;
end;

function GetChartWorkAreaWidth(var chart:FCChart):double;
begin
  GetChartWorkAreaWidth := chart.size.cx - chart.leftVScaleWidth - chart.rightVScaleWidth - chart.rightSpace - chart.offsetX;
end;

function GetChartX(var chart:FCChart; idx:integer):double;
begin
  GetChartX := chart.leftVScaleWidth + double(idx - chart.firstVisibleIndex) * chart.hScalePixel + chart.hScalePixel / 2 + chart.offsetX;
end;

function GetChartIndexByDate(var chart:FCChart; date:double):integer;
var
  length:integer;
  idx:integer;
  i:integer;
begin
  idx := -1;
  length := High(chart.data) - Low(chart.data) + 1;
  for i := 0 to length - 1 do
    begin
    if chart.data[i].date = date then
      begin
      idx := i;
      break;
      end;
    end;
  GetChartIndexByDate := idx;
end;

function GetChartDateByIndex(var chart:FCChart; idx:integer):double;
var
  length:integer;
  date:double;
begin
  length := High(chart.data) - Low(chart.data) + 1;
  if length > 0 then
    begin
    if (idx >= 0) and (idx < length) then
      date := chart.data[idx].date;
    end;
  GetChartDateByIndex := date;
end;

function GetChartY(var chart:FCChart; divIndex:integer; value:double):double;
var
  cValue, cMax, cMin:double;
  candleHeight, volHeight, indHeight:double;
  rate:double;
  res:double;
begin
  cValue := 0;
  cMax := 0;
  cMin := 0;
  rate := 0;
  res := 0;
  candleHeight := GetCandleDivHeight(chart);
  volHeight := GetVolDivHeight(chart);
  indHeight := GetIndDivHeight(chart);
  if divIndex = 0 then
    begin
    if chart.candleMax > chart.candleMin then
      begin
      cValue := value;
      cMax := chart.candleMax;
      cMin := chart.candleMin;
      if chart.vScaleType <> 'standard' then
        begin
        if cValue > 0 then
          cValue := Log10(cValue)
        else if cValue < 0 then
          cValue := -Log10(-cValue);
        if cMax > 0 then
          cMax := Log10(cMax)
        else if cMax < 0 then
          cMax := -Log10(-cMax);
        if cMin > 0 then
          cMin := Log10(cMin)
        else if cMin < 0 then
          cMin := -Log10(-cMin);
        end;
      rate := (cValue - cMin) / (cMax - cMin);
      res := candleHeight - chart.candlePaddingBottom - (candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom) * rate;
      end
    else
      begin
      res := 0;
      end
    end
  else if divIndex = 1 then
    begin
    if chart.volMax > chart.volMin then
      begin
      rate := (value - chart.volMin) / (chart.volMax - chart.volMin);
      res := candleHeight + volHeight - chart.volPaddingBottom - (volHeight - chart.volPaddingTop - chart.volPaddingBottom) * rate;
      end
    else
      begin
      res := 0;
      end
    end
  else if divIndex = 2 then
    begin
    if chart.indMax > chart.indMin then
      begin
      rate := (value - chart.indMin) / (chart.indMax - chart.indMin);
      res := candleHeight + volHeight + indHeight - chart.indPaddingBottom - (indHeight - chart.indPaddingTop - chart.indPaddingBottom) * rate;
      end
    else
      begin
      res := 0;
      end  
    end;
  GetChartY := res;
end;

function GetChartYInRight(var chart:FCChart; divIndex:integer; value:double):double;
var
  cValue, cMax, cMin:double;
  candleHeight, volHeight, indHeight:double;
  rate:double;
  res:double;
begin
  cValue := 0;
  cMax := 0;
  cMin := 0;
  rate := 0;
  res := 0;
  candleHeight := GetCandleDivHeight(chart);
  volHeight := GetVolDivHeight(chart);
  indHeight := GetIndDivHeight(chart);
  if divIndex = 0 then
    begin
    if chart.candleMaxRight > chart.candleMinRight then
      begin
      cValue := value;
      cMax := chart.candleMaxRight;
      cMin := chart.candleMinRight;
      if chart.vScaleType <> 'standard' then
        begin
        if cValue > 0 then
          cValue := Log10(cValue)
        else if cValue < 0 then
          cValue := -Log10(-cValue);
        if cMax > 0 then
          cMax := Log10(cMax)
        else if cMax < 0 then
          cMax := -Log10(-cMax);
        if cMin > 0 then
          cMin := Log10(cMin)
        else if cMin < 0 then
          begin
          cMin := -Log10(-cMin);
          end;
        end;
      rate := (cValue - cMin) / (cMax - cMin);
      res := candleHeight - chart.candlePaddingBottom - (candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom) * rate;
      end
    else
      begin
      res := 0;
      end
    end
  else if divIndex = 1 then
    begin
    if chart.volMaxRight > chart.volMinRight then
      begin
      rate := (value - chart.volMinRight) / (chart.volMaxRight - chart.volMinRight);
      res := candleHeight + volHeight - chart.volPaddingBottom - (volHeight - chart.volPaddingTop - chart.volPaddingBottom) * rate;
      end
    else
      res := 0;
    end
  else if divIndex = 2 then
    begin
    if chart.indMaxRight > chart.indMinRight then
      begin
      rate := (value - chart.indMinRight) / (chart.indMaxRight - chart.indMinRight);
      res := candleHeight + volHeight + indHeight - chart.indPaddingBottom - (indHeight - chart.indPaddingTop - chart.indPaddingBottom) * rate;
      end
    else
      res := 0;
    end;
  GetChartYInRight := res;
end;

function GetChartValue(var chart:FCChart; point:FCPoint):double;
var
  res, cMax, cMin:double;
  candleHeight, volHeight, indHeight:double;
  rate:double;
begin
  res := 0;
  cMax := 0;
  cMin := 0;
  rate := 0;
  candleHeight := GetCandleDivHeight(chart);
  volHeight := GetVolDivHeight(chart);
  indHeight := GetIndDivHeight(chart);
  if point.y <= candleHeight then
    begin
    if candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom > 0 then
    begin
      rate := (candleHeight - chart.candlePaddingBottom - point.y) / (candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom);
      cMin := chart.candleMin;
      cMax := chart.candleMax;
      if chart.VScaleType <> 'standard' then
        begin
        if cMax > 0 then
          cMax := Log10(cMax)
        else if cMax < 0 then
          cMax := -Log10(-cMax);
        if cMin > 0 then
          cMin := Log10(cMin)
        else if cMin < 0 then
          cMin := -Log10(-cMin);
        end;
      res := cMin + (cMax - cMin) * rate;
      if chart.VScaleType <> 'standard' then
          res := Power(10, res);
      end
    end
  else if (point.y > candleHeight) and (point.y <= candleHeight + volHeight) then
    begin
    if volHeight - chart.volPaddingTop - chart.volPaddingBottom > 0 then
    begin
      rate := (volHeight - chart.volPaddingBottom - (point.y - candleHeight)) / (volHeight - chart.volPaddingTop - chart.volPaddingBottom);
      res := chart.volMin + (chart.volMax - chart.volMin) * rate;
    end
    end
  else if (point.y > candleHeight + volHeight) and (point.y <= candleHeight + volHeight + indHeight) then
    begin
    if indHeight - chart.indPaddingTop - chart.indPaddingBottom > 0 then
    begin
      rate := (indHeight - chart.indPaddingBottom - (point.Y - candleHeight - volHeight)) / (indHeight - chart.indPaddingTop - chart.indPaddingBottom);
      res := chart.indMin + (chart.indMax - chart.indMin) * rate;
    end
    end;
  GetChartValue := res;
end;

procedure GetLRBandRange(var chart:FCChart; var plot:FCPlot; a:double; b:double);
var
  highMax:double;
  lowMin:double;
  bIndex:integer;
  eIndex:integer;
  tempBIndex:integer;
  tempEIndex:integer;
  high:double;
  low:double;
  midValue:double;
  i:integer;
  newLength:integer;
begin
  bIndex := GetChartIndexByDate(chart, plot.key1);
	eIndex := GetChartIndexByDate(chart, plot.key2);
  if bIndex <> eIndex then
  begin
    if bIndex < eIndex then
      tempBIndex := bIndex
    else
      tempBIndex := bIndex;
    if bIndex < eIndex then
      tempEIndex := eIndex
    else
      tempEIndex := bIndex;
    bIndex := tempBIndex;
    eIndex := tempEIndex;
    newLength := eIndex - bIndex + 1;
    high := 0;
    low := 0;
    midValue := 0;
    highMax := 0;
    lowMin := 0;
    for i := bIndex to eIndex do
      begin
        high := chart.data[i].high;
        low := chart.data[i].low;
        midValue := (i - bIndex + 1) * a + b;
        if i = bIndex then
          begin
          highMax := high - midValue;
          lowMin := midValue - low;
          end
        else
          begin
            if highMax < high - midValue then
              highMax := high - midValue;
            if lowMin < midValue - low then
              lowMin := midValue - low;
          end;
      end;
    chart.upSubValue := highMax;
    chart.downSubValue := lowMin;
  end;
end; 

function GetCandleDivValue(var chart:FCChart; point:FCPoint):double;
var
  rate, res, cMax, cMin:double;
  candleHeight:double;
begin
  res := 0;
  candleHeight := GetCandleDivHeight(chart);
  rate := 0;
  if candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom > 0 then
    rate := (candleHeight - chart.candlePaddingBottom - point.y) / (candleHeight - chart.candlePaddingTop - chart.candlePaddingBottom);
  cMin := chart.candleMin;
  cMax := chart.candleMax;
  if chart.vScaleType <> 'standard' then
    begin
    if cMax > 0 then
      cMax := Log10(cMax)
    else if cMax < 0 then
      cMax := -Log10(-cMax);
    if cMin > 0 then
      cMin := Log10(cMin)
    else if cMin < 0 then
      begin
      cMin := -Log10(-cMin);
      end;
    end;
  res := cMin + (cMax - cMin) * rate;
  if chart.vScaleType <> 'standard' then
    GetCandleDivValue := power(10, res)
  else
    GetCandleDivValue := res;
end;

procedure CheckChartLastVisibleIndex(var chart:FCChart);
var
  dataCount:integer;
  workingAreaWidth:double;
  maxVisibleRecord:integer;
begin
  dataCount := High(chart.data) - Low(chart.data) + 1;
  workingAreaWidth := GetChartWorkAreaWidth(chart);
  maxVisibleRecord := GetChartMaxVisibleCount(chart, chart.hScalePixel, workingAreaWidth);
  if chart.firstVisibleIndex < 0 then
    chart.firstVisibleIndex := 0;
  if (chart.lastVisibleIndex >= chart.firstVisibleIndex + maxVisibleRecord - 1) or (chart.lastVisibleIndex < dataCount - 1) then
      chart.lastVisibleIndex := chart.firstVisibleIndex + maxVisibleRecord - 1;
  if chart.lastVisibleIndex > dataCount - 1 then
    chart.lastVisibleIndex := dataCount - 1;
  if (dataCount > 0) and (chart.lastVisibleIndex <> -1) then
    begin
    chart.lastVisibleKey := chart.data[chart.lastVisibleIndex].date;
    if chart.lastVisibleIndex = dataCount - 1 then
        chart.lastRecordIsVisible := true
    else
        chart.lastRecordIsVisible := false;
    end
  else
    begin
    chart.lastVisibleKey := 0;
    chart.lastRecordIsVisible := true;
    end;
end;

procedure ResetChartVisibleRecord(var chart:FCChart);
var
  rowsCount:integer;
  workingAreaWidth:double;
  maxVisibleRecord:integer;
  idx:integer;
begin
  rowsCount := High(chart.data) - Low(chart.data) + 1;
  workingAreaWidth := GetChartWorkAreaWidth(chart);
  maxVisibleRecord := 0;
  if chart.autoFillHScale then
    begin
    if (workingAreaWidth > 0) and (rowsCount > 0) then
      begin
      chart.hScalePixel := workingAreaWidth / double(rowsCount);
      chart.firstVisibleIndex := 0;
      chart.lastVisibleIndex := rowsCount - 1;
      end;
    end
  else
    begin
    maxVisibleRecord := GetChartMaxVisibleCount(chart, chart.hScalePixel, workingAreaWidth);
    if rowsCount = 0 then
      begin
      chart.firstVisibleIndex := -1;
      chart.lastVisibleIndex := -1;
      end
    else
      if rowsCount < maxVisibleRecord then
        begin
        chart.lastVisibleIndex := rowsCount - 1;
        chart.firstVisibleIndex := 0;
        end
      else
        begin
          if (chart.firstVisibleIndex <> -1) and (chart.lastVisibleIndex <> -1) and (chart.LastRecordIsVisible = false) then
            begin
            idx := GetChartIndexByDate(chart, chart.lastVisibleKey);
            if idx <> -1 then
              chart.lastVisibleIndex := idx;
            chart.firstVisibleIndex := chart.lastVisibleIndex - maxVisibleRecord + 1;
            if chart.firstVisibleIndex < 0 then
              begin
              chart.firstVisibleIndex := 0;
              chart.lastVisibleIndex := chart.firstVisibleIndex + maxVisibleRecord;
              CheckChartLastVisibleIndex(chart);
              end;
            end
          else 
            begin
            chart.lastVisibleIndex := rowsCount - 1;
            chart.firstVisibleIndex := chart.lastVisibleIndex - maxVisibleRecord + 1;
            if chart.firstVisibleIndex > chart.lastVisibleIndex then
              chart.firstVisibleIndex := chart.lastVisibleIndex;
            end;
        end;
      end;
end;

procedure setChartVisibleIndex(var chart:FCChart; firstVisibleIndex:integer; lastVisibleIndex:integer);
var
  xScalePixel:double;
  length:integer;
begin
  xScalePixel := GetChartWorkAreaWidth(chart) / double(firstVisibleIndex - lastVisibleIndex + 1);
  length := High(chart.data) - Low(chart.data) + 1;
  if xScalePixel < 1000000 then
    begin
      chart.firstVisibleIndex := firstVisibleIndex;
      chart.lastVisibleIndex := lastVisibleIndex;
      //设置最后一条记录是否可见
      if lastVisibleIndex <> length - 1 then
        chart.lastRecordIsVisible := false
      else
        begin
        chart.lastRecordIsVisible := true;
        end;
      chart.hScalePixel := xScalePixel;
      CheckChartLastVisibleIndex(chart);
    end;
end;

procedure GetCandleRange(var chart:FCChart; plot:FCPlot);
var
  bIndex:integer;
  eIndex:integer;
  tempBIndex:integer;
  tempEIndex:integer;
  highMax:double;
  lowMin:double;
  i:integer;
  newLength:integer;
begin
  bIndex := GetChartIndexByDate(chart, plot.key1);
	eIndex := GetChartIndexByDate(chart, plot.key2);
  if bIndex <> eIndex then
    begin
    if bIndex < eIndex then
      tempBIndex := bIndex
    else
      tempBIndex := bIndex;
    if bIndex < eIndex then
      tempEIndex := eIndex
    else
      tempEIndex := bIndex;
    bIndex := tempBIndex;
    eIndex := tempEIndex;
    newLength := eIndex - bIndex + 1;
    highMax := 0;
    lowMin := 0;
    for i := bIndex to eIndex do
      begin
        if i = bIndex then
          begin
          highMax := chart.data[i].high;
          lowMin := chart.data[i].low;
          end
        else
          begin
            if highMax < chart.data[i].high then
              highMax := chart.data[i].high;
            if lowMin > chart.data[i].low then
              lowMin := chart.data[i].low;
          end;
      end;
    chart.nHighChart := highMax;
    chart.nLowChart := lowMin;
    end;
end;

procedure ChartGridScale(var chart:FCChart; minValue:double; maxValue:double; yLen:double; maxSpan:double; minSpan:double; defCount:integer);
var
  subValue:double;
  nMinCount:integer;
  nMaxCount:integer;
  nCount:integer;
  logStep:double;
  start:boolean;
  divisor:double;
  i:integer;
  nTemp:integer;
begin
  if (defCount > 0) and (maxSpan > 0) and (minSpan > 0) then
    begin
    subValue := maxValue - minValue;
    nMinCount := Ceil(yLen / maxSpan);
    nMaxCount := Floor(yLen / minSpan);
    nCount := defCount;
		logStep := subValue / nCount;
		start := false;
		divisor := 0;
		i := 15;
		nTemp := 0;
		chart.gridStepChart := 0;
		chart.gridDigitChart := 0;
    if nMinCount > nCount then
      nCount := nMinCount;
    if nMaxCount < nCount then
      nCount := nMaxCount;
    if nCount < 1 then
      nCount := 1;
    while i >= -6 do
    begin
      divisor := Power(10.0, i);
      if divisor < 1 then
        begin
				chart.gridDigitChart := chart.gridDigitChart + 1;
        end;
      nTemp := Floor(logStep / divisor);
      if start then
        begin
				if nTemp < 4 then
          begin
					if chart.gridDigitChart > 0 then
						chart.gridDigitChart := chart.gridDigitChart - 1;
          end
				else if (nTemp >= 4) and (nTemp <= 6) then
          begin
					nTemp := 5;
					chart.gridStepChart := chart.gridStepChart + nTemp * divisor;
          end
				else
          begin
					chart.gridStepChart := chart.gridStepChart + 10 * divisor;
					if chart.gridDigitChart > 0 then
						chart.gridDigitChart := chart.gridDigitChart - 1;
          end;
				break
        end
			else if nTemp > 0 then
        begin
				chart.gridStepChart := nTemp * divisor + chart.gridStepChart;
				logStep := logStep - chart.gridStepChart;
				start := true;
			  end;
			i := i - 1;
    end;
  end;
end;

procedure ZoomOutChart(var chart:FCChart);
var
  dataCount:integer;
  hScalePixel:double;
  oldX:double;
  pureH:double;
  oriMax:double;
  max:integer;
  deal:integer;
  findex:integer;
  lindex:integer;
  newX:double;
  sX:double;
begin
  dataCount := High(chart.data) - Low(chart.data) + 1;
  hScalePixel := 0;
  oldX := 0;
  pureH := 0;
  oriMax := -1;
  max := -1;
  deal := 0;
  findex := -1;
  lindex := -1;
  newX := 0;
  if chart.autoFillHScale = false then
    begin
    hScalePixel := chart.hScalePixel;
    oldX := GetChartX(chart, chart.crossStopIndex);
    if chart.targetOldX = 0 then
			chart.targetOldX := oldX;
    pureH := GetChartWorkAreaWidth(chart);
    findex := chart.firstVisibleIndex;
    lindex := chart.lastVisibleIndex;
    if hScalePixel < pureH then
      begin
      oriMax := GetChartMaxVisibleCount(chart, hScalePixel, pureH);
      if dataCount < oriMax then
        deal := 1;
      if hScalePixel > 3 then
        hScalePixel := hScalePixel + 1
      else
        begin
        if hScalePixel = 1 then
            hScalePixel := 2
        else
          begin
          hScalePixel := hScalePixel * 1.5;
            if hScalePixel > 3 then
              hScalePixel := double(trunc(hScalePixel));
          end;
        end;
      max := GetChartMaxVisibleCount(chart, hScalePixel, pureH);
      if dataCount >= max then
        begin
        if deal = 1 then
          lindex := dataCount - 1;
        findex := lindex - max + 1;
        if findex < 0 then
          findex := 0;
        end;
      end;
    chart.hScalePixel := hScalePixel;
    sX := chart.targetOldX;
    findex := chart.crossStopIndex;
    while sX >= chart.leftVScaleWidth + chart.hScalePixel / 2 do
    begin
      findex := findex - 1;
      chart.offsetX := sX - chart.leftVScaleWidth - chart.hScalePixel / 2;
      sX := sX - chart.hScalePixel;
    end;
    findex := findex + 1;
    chart.firstVisibleIndex := findex;
    chart.lastVisibleIndex := lindex;
    CheckChartLastVisibleIndex(chart);
    CalculateChartMaxMin(chart);
  end;
end;

procedure ZoomInChart(var chart:FCChart);
var
  dataCount:integer;
  hScalePixel:double;
  oldX:double;
  pureH:double;
  oriMax:double;
  max:integer;
  deal:integer;
  findex:integer;
  lindex:integer;
  newX:double;
  sX:double;
begin
  dataCount := High(chart.data) - Low(chart.data) + 1;
  hScalePixel := 0;
  oldX := 0;
  pureH := 0;
  oriMax := -1;
  max := -1;
  deal := 0;
  findex := -1;
  lindex := -1;
  newX := 0;
  if chart.autoFillHScale = false then
    begin
    hScalePixel := chart.hScalePixel;
    oldX := GetChartX(chart, chart.crossStopIndex);
    if chart.targetOldX2 = 0 then
			chart.targetOldX2 := oldX;
    pureH := GetChartWorkAreaWidth(chart);
    findex := chart.firstVisibleIndex;
    lindex := chart.lastVisibleIndex;
    if hScalePixel > 3 then
      hScalePixel := hScalePixel - 1
    else
      begin
      hScalePixel := hScalePixel * 2 / 3;
      if hScalePixel > 3 then
        hScalePixel := double(trunc(hScalePixel));
      end;
    max := GetChartMaxVisibleCount(chart, hScalePixel, pureH);
    if max >= dataCount then
      begin
      if hScalePixel < 1 then
        hScalePixel := pureH / double(max);
      findex := 0;
      lindex := dataCount - 1;
      end
    else
      begin
      findex := lindex - max + 1;
      if findex < 0 then
          findex := 0;
      end;
    chart.hScalePixel := hScalePixel;
    sX := chart.targetOldX2;
    findex := chart.crossStopIndex;
		while sX >= chart.leftVScaleWidth + chart.hScalePixel / 2 do
    begin
      findex := findex - 1;
      chart.offsetX := sX - chart.leftVScaleWidth - chart.hScalePixel / 2;
      sX := sX - chart.hScalePixel;
    end;
    findex := findex + 1;
    chart.firstVisibleIndex := findex;
    chart.lastVisibleIndex := lindex;
    CheckChartLastVisibleIndex(chart);
    CalculateChartMaxMin(chart);
  end;
end;

procedure ClearDataArr(var chart:FCChart);
begin
  SetLength(chart.allema12, 0);
  SetLength(chart.allema26, 0);
  SetLength(chart.alldifarr, 0);
  SetLength(chart.alldeaarr, 0);
  SetLength(chart.allmacdarr, 0);
  SetLength(chart.bollUp, 0);
  SetLength(chart.bollDown, 0);
  SetLength(chart.bollMid, 0);
  SetLength(chart.bias1, 0);
  SetLength(chart.bias2, 0);
  SetLength(chart.bias3, 0);
  SetLength(chart.kdjK, 0);
  SetLength(chart.kdjD, 0);
  SetLength(chart.kdjJ, 0);
  SetLength(chart.rsi1, 0);
  SetLength(chart.rsi2, 0);
  SetLength(chart.rsi3, 0);
  SetLength(chart.roc, 0);
  SetLength(chart.rocMa, 0);
  SetLength(chart.wr1, 0);
  SetLength(chart.wr2, 0);
  SetLength(chart.cci, 0);
  SetLength(chart.bbi, 0);
  SetLength(chart.trix, 0);
  SetLength(chart.trixMa, 0);
  SetLength(chart.dma1, 0);
  SetLength(chart.dma2, 0);
  SetLength(chart.ma5, 0);
  SetLength(chart.ma10, 0);
  SetLength(chart.ma20, 0);
  SetLength(chart.ma30, 0);
  SetLength(chart.ma120, 0);
  SetLength(chart.ma250, 0);
end;

procedure CalcChartIndicator(var chart:FCChart);
var
  closeArr:DoubleArray;
  highArr:DoubleArray;
  lowArr:DoubleArray;
  dataCount:integer; 
  i:integer;
begin
  dataCount := High(chart.data) - Low(chart.data) + 1;
  ClearDataArr(chart);
  SetLength(closeArr, dataCount);
  SetLength(highArr, dataCount);
  SetLength(lowArr, dataCount);
  SetLength(chart.closearr, dataCount);
  for i := 0 to dataCount - 1 do
  begin
    chart.closeArr[i] := chart.data[i].close;
    closeArr[i] := chart.data[i].close;
    highArr[i] := chart.data[i].high;
    lowArr[i] := chart.data[i].low;
  end;
  if chart.mainIndicator = 'MA' then
    begin
		MaValue(closeArr, 5, chart.ma5);
		MaValue(closeArr, 10, chart.ma10);
		MaValue(closeArr, 20, chart.ma20);
		MaValue(closeArr, 30, chart.ma30);
		MaValue(closeArr, 120, chart.ma120);
		MaValue(closeArr, 250, chart.ma250);
    end
	else if chart.mainIndicator = 'BOLL' then
    begin
		GetBollData(closeArr, 20, chart.bollUp, chart.bollMid, chart.bollDown);
    end;
  if chart.ShowIndicator = 'MACD' then
    begin
    SetLength(chart.allema12, dataCount);
    SetLength(chart.allema26, dataCount);
    SetLength(chart.alldifarr, dataCount);
    SetLength(chart.alldeaarr, dataCount);
    SetLength(chart.allmacdarr, dataCount);
		chart.allema12[0] := chart.closearr[0];
		chart.allema26[0] := chart.closearr[0];
		chart.alldeaarr[0] := 0;
    for i := 1 to dataCount - 1 do
    begin
      chart.allema12[i] := GetEMA(12, chart.closearr[i], chart.allema12[i - 1]);
			chart.allema26[i] := GetEMA(26, chart.closearr[i], chart.allema26[i - 1]);
    end;
		GetDIF(chart.allema12, chart.allema26, chart.alldifarr);
    for i := 1 to dataCount - 1 do
    begin
      chart.alldeaarr[i] := chart.alldeaarr[i - 1] * 8 / 10 + chart.alldifarr[i] * 2 / 10;
    end;
		GetMACD(chart.alldifarr, chart.alldeaarr, chart.allmacdarr);
    end
	else if chart.ShowIndicator = 'BIAS' then
		GetBIASData(chart.closearr, 6, 12, 24, chart.bias1, chart.bias2, chart.bias3)
	else if chart.ShowIndicator = 'TRIX' then
		GetTRIXData(chart.closearr, 10, 50, chart.trix, chart.trixMa)
	else if chart.ShowIndicator = 'CCI' then
		GetCCIData(closeArr, highArr, lowArr, 14, chart.cci)
	else if chart.ShowIndicator = 'BBI' then
		GetBBIData(closeArr, 3, 6, 12, 24, chart.bbi)
	else if chart.ShowIndicator = 'ROC' then
		GetRocData(closeArr, 12, 6, chart.roc, chart.rocMa)
	else if chart.ShowIndicator = 'WR' then
		GetWRData(closeArr, highArr, lowArr, 5, 10, chart.wr1, chart.wr2)
	else if chart.ShowIndicator = 'DMA' then
		GetDMAData(closeArr, 10, 50, chart.dma1, chart.dma2)
	else if chart.ShowIndicator = 'RSI' then
		GetRSIData(closeArr, 6, 12, 24, chart.rsi1, chart.rsi2, chart.rsi3)
	else if chart.ShowIndicator = 'KDJ' then
		GetKDJData( highArr, lowArr, closeArr, 9, 3, 3, chart.kdjK, chart.kdjD, chart.kdjJ);
	CalculateChartMaxMin(chart);
end;

function SelectLines(var chart:FCChart; mp:FCPoint; divIndex:integer; datas:DoubleArray; curIndex:integer):boolean;
var
  length:integer;
  topY:double;
  idx:integer;
  scaleX:double;
  judgeTop:double;
  judgeScaleX:double;
  leftIndex:integer;
  rightIndex:integer;
  lineWidth:double;
  judgeX:double;
  judgeY:double;
  judgeW:double;
  judgeH:double;
  leftValue:double;
  rightValue:double;
  res:boolean;
begin
  length := High(chart.data) - Low(chart.data) + 1;
  topY := 0;
  idx := 0;
  scaleX := 0;
  judgeTop := 0;
  judgeScaleX := 0;
  leftIndex := 0;
  rightIndex := 0;
  lineWidth := 0;
  judgeX := 0;
  judgeY := 0;
  judgeW := 0;
  judgeH := 0;
  leftValue := 0;
  rightValue := 0;
  res := false;
  if length > 0 then
    begin
    topY := GetChartY(chart, divIndex, datas[curIndex]);
    if chart.hScalePixel <= 1 then
      begin
      if (mp.y >= topY - 8) and (mp.y <= topY + 8) then
        res := true;
      end
    else
      begin
      idx := curIndex;
      scaleX := GetChartX(chart, idx);
      judgeTop := 0.0;
      judgeScaleX := scaleX;
      if mp.x >= scaleX then
        begin
        leftIndex := curIndex + 1;
        if curIndex < chart.lastVisibleIndex then
          begin
          rightValue := datas[leftIndex];
          judgeTop := GetChartY(chart, divIndex, rightValue);
          end
        else
          judgeTop := topY;
        end
      else
        begin
        judgeScaleX := scaleX - chart.hScalePixel;
        rightIndex := curIndex - 1;
        if curIndex > 0 then
          begin
          leftValue := datas[rightIndex];
          judgeTop := GetChartY(chart, divIndex, leftValue);
          end
        else
          judgeTop := topY;
        end;
      lineWidth := 4.0;
      judgeX := 0.0;
      judgeY := 0.0;
      judgeW := 0.0;
      judgeH := 0.0;
      if judgeTop >= topY then
        begin
        judgeX := judgeScaleX;
        judgeY := topY - 2 - lineWidth;
        judgeW := chart.hScalePixel;
        if judgeTop - topY + lineWidth < 4 then
          judgeH := 4
        else
          judgeH := judgeTop - topY + 4 + lineWidth;
        end
      else
        begin
        judgeX := judgeScaleX;
        judgeY := judgeTop - 2 - lineWidth / 2;
        judgeW := chart.hScalePixel;
        if topY - judgeTop + lineWidth < 4 then
            judgeH := 4
        else
            judgeH := topY - judgeTop + 4 + lineWidth;
        end;
      if (mp.x >= judgeX) and (mp.x <= judgeX + judgeW) and (mp.y >= judgeY) and (mp.y <= judgeY + judgeH) then
        res := true;
      end;
    end;
  SelectLines := res;
end;

function SelectLinesInRight(var chart:FCChart; mp:FCPoint; divIndex:integer; datas:DoubleArray; curIndex:integer):boolean;
var
  length:integer;
  topY:double;
  idx:integer;
  scaleX:double;
  judgeTop:double;
  judgeScaleX:double;
  leftIndex:integer;
  rightIndex:integer;
  lineWidth:double;
  judgeX:double;
  judgeY:double;
  judgeW:double;
  judgeH:double;
  leftValue:double;
  rightValue:double;
  res:boolean;
begin
  res := false;
  length := High(chart.data) - Low(chart.data) + 1;
  topY := 0;
  idx := 0;
  scaleX := 0;
  judgeTop := 0;
  judgeScaleX := 0;
  leftIndex := 0;
  rightIndex := 0;
  lineWidth := 0;
  judgeX := 0;
  judgeY := 0;
  judgeW := 0;
  judgeH := 0;
  leftValue := 0;
  rightValue := 0;
  if length > 0 then
    begin
    topY := GetChartYInRight(chart, divIndex, datas[curIndex]);
    if chart.hScalePixel <= 1 then
      begin
      if (mp.y >= topY - 8) and (mp.y <= topY + 8) then
        res := true;
      end
    else
      begin
      idx := curIndex;
      scaleX := GetChartX(chart, idx);
      judgeTop := 0.0;
      judgeScaleX := scaleX;
      if mp.x >= scaleX then
        begin
        leftIndex := curIndex + 1;
        if curIndex < chart.lastVisibleIndex then
          begin
          rightValue := datas[leftIndex];
          judgeTop := GetChartYInRight(chart, divIndex, rightValue);
          end
        else
          judgeTop := topY;
        end
      else
        begin
        judgeScaleX := scaleX - chart.hScalePixel;
        rightIndex := curIndex - 1;
        if curIndex > 0 then
          begin
          leftValue := datas[rightIndex];
          judgeTop := GetChartYInRight(chart, divIndex, leftValue);
          end
        else
          judgeTop := topY;
        end;
      end;
      lineWidth := 4.0;
      judgeX := 0.0;
      judgeY := 0.0;
      judgeW := 0.0;
      judgeH := 0.0;
      if judgeTop >= topY then
        begin
        judgeX := judgeScaleX;
        judgeY := topY - 2 - lineWidth;
        judgeW := chart.hScalePixel;
        if judgeTop - topY + lineWidth < 4 then
          judgeH := 4
        else
          judgeH := judgeTop - topY + 4 + lineWidth;
        end
      else
        begin
        judgeX := judgeScaleX;
        judgeY := judgeTop - 2 - lineWidth / 2;
        judgeW := chart.hScalePixel;
        if topY - judgeTop + lineWidth < 4 then
            judgeH := 4
        else
            judgeH := topY - judgeTop + 4 + lineWidth;
        end;
      if (mp.x >= judgeX) and (mp.x <= judgeX + judgeW) and (mp.y >= judgeY) and (mp.y <= judgeY + judgeH) then
        res := true;
    end;
  SelectLinesInRight := res;
end;

procedure SelectShape(var chart:FCChart; mp:FCPoint);
var
  candleHeight, volHeight, indHeight:double;
  idx:integer;
  i:integer;
  shapeLength:integer;
  volY:double;
  zeroY:double;
  isTrend:boolean;
  highY:double;
  lowY:double;
  shape:BaseShape;
  minValue:double;
  maxValue:double;
begin
  candleHeight := GetCandleDivHeight(chart);
  volHeight := GetVolDivHeight(chart);
  indHeight := GetIndDivHeight(chart);
  chart.selectShape := '';
  chart.selectShapeEx := '';
  idx := GetChartIndex(chart, mp);
  volY := 0;
  zeroY := 0;
  highY := 0;
  lowY := 0;
  shapeLength := High(chart.shapes) - Low(chart.shapes) + 1;
  isTrend := false;
  if chart.cycle = 'trend' then
    isTrend := true;
  if (idx <> -1) and (shapeLength > 0) then
    begin
    if (mp.y >= candleHeight + volHeight) and (mp.y <= candleHeight + volHeight + indHeight) then
      begin
      if chart.showIndicator = 'MACD' then
        begin
        if SelectLines(chart, mp, 2, chart.allmacdarr, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'MACD';
          end;
        if SelectLines(chart, mp, 2, chart.alldifarr, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'DIF';
          end
        else if SelectLines(chart, mp, 2, chart.alldeaarr, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'DEA';
          end;
        end
      else if chart.showIndicator = 'KDJ' then
        begin
        if SelectLines(chart, mp, 2, chart.kdjK, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'K';
          end
        else if SelectLines(chart, mp, 2, chart.kdjD, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'D';
          end
        else if SelectLines(chart, mp, 2, chart.kdjJ, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'J';
          end;
        end
      else if chart.showIndicator = 'RSI' then
        begin
        if SelectLines(chart, mp, 2, chart.rsi1, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '6';
          end
        else if SelectLines(chart, mp, 2, chart.rsi2, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '12';
          end
        else if SelectLines(chart, mp, 2, chart.rsi3, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '24';  
          end;
        end 
      else if chart.showIndicator = 'BIAS' then
        begin
        if SelectLines(chart, mp, 2, chart.bias1, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '1';
          end
        else if SelectLines(chart, mp, 2, chart.bias2, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '2';
          end
        else if SelectLines(chart, mp, 2, chart.bias3, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '3';  
          end;
        end
      else if chart.showIndicator = 'ROC' then
        begin
        if SelectLines(chart, mp, 2, chart.roc, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'ROC';
          end
        else if SelectLines(chart, mp, 2, chart.rocMa, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'ROCMA';       
          end;
        end  
      else if chart.showIndicator = 'WR' then
        begin
        if SelectLines(chart, mp, 2, chart.wr1, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := '1';
          end
        else if SelectLines(chart, mp, 2, chart.wr2, idx) then
          begin
          chart.selectShape := 'WR';
          chart.selectShapeEx := '2';
          end;
        end
      else if chart.showIndicator = 'CCI' then
        begin
        if SelectLines(chart, mp, 2, chart.cci, idx) then
          chart.selectShape := chart.showIndicator; 
        end
      else if chart.showIndicator = 'BBI' then
        begin
        if SelectLines(chart, mp, 2, chart.bbi, idx) then
          chart.selectShape := chart.showIndicator;
        end
      else if chart.showIndicator = 'TRIX' then
        begin
        if SelectLines(chart, mp, 2, chart.trix, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'TRIX';
          end
        else if SelectLines(chart, mp, 2, chart.trixMa, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'TRIXMA';
          end;
        end
      else if chart.showIndicator = 'DMA' then
        begin
        if SelectLines(chart, mp, 2, chart.dma1, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'DIF';
          end
        else if SelectLines(chart, mp, 2, chart.dma2, idx) then
          begin
          chart.selectShape := chart.showIndicator;
          chart.selectShapeEx := 'DIFMA';
          end;
        end
      end
    else if (mp.y >= candleHeight) and (mp.y <= candleHeight + volHeight) then
      begin
      volY := GetChartY(chart, 1, chart.data[idx].volume);
      zeroY := GetChartY(chart, 1, 0);
      if volY > zeroY then
        begin
        maxValue := volY;
        minValue := zeroY;
        end
      else
        begin
        minValue := volY;
        maxValue := zeroY;
        end;
      if (mp.y >= minValue) and (mp.y <= maxValue) then
        begin
        chart.selectShape := 'VOL';
        end;
      end
    else if (mp.y >= 0) and (mp.y <= candleHeight) then
      isTrend :=  false;
      if chart.cycle = 'trend' then
        isTrend := true;
      if isTrend = false then
        if chart.mainIndicator = 'BOLL' then
          begin
          if SelectLines(chart, mp, 0, chart.bollMid, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := 'MID';
            end
          else if SelectLines(chart, mp, 0, chart.bollUp, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := 'UP';
            end
          else if SelectLines(chart, mp, 0, chart.bollDown, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := 'DOWN';
            end;
          end
        else if chart.mainIndicator = 'MA' then
          begin
          if SelectLines(chart, mp, 0, chart.ma5, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := '5';
            end
          else if SelectLines(chart, mp, 0, chart.ma10, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := '10';
            end
          else if SelectLines(chart, mp, 0, chart.ma20, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := '20';
            end
          else if SelectLines(chart, mp, 0, chart.ma30, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := '30';
            end
          else if SelectLines(chart, mp, 0, chart.ma120, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := '120';
            end
          else if SelectLines(chart, mp, 0, chart.ma250, idx) then
            begin
            chart.selectShape := chart.mainIndicator;
            chart.selectShapeEx := '250';
            end;
          end;
      if chart.selectShape = '' then
        begin
        highY := GetChartY(chart, 0, chart.data[idx].high);
        lowY := GetChartY(chart, 0, chart.data[idx].low);
        if isTrend then
          begin
          if SelectLines(chart, mp, 0, chart.closeArr, idx) then
            chart.selectShape := 'CANDLE';
          end
        else
          begin
          if lowY > highY then
            begin
            minValue := highY;
            maxValue := lowY;
            end
          else
            begin
            minValue := lowY;
            maxValue := highY;
            end;
          if (mp.y >= minValue) and (mp.y <= maxValue) then
            chart.selectShape := 'CANDLE';
          end;
        end;
    if shapeLength > 0 then
      begin
      for i := 0 to shapeLength - 1 do
      begin
        shape := chart.shapes[i];
        if shape.leftOrRight then
          begin
          if SelectLines(chart, mp, shape.divIndex, shape.datas, idx) then
              chart.selectShape := shape.shapeName;
              break;
          end
        else
          begin
          if SelectLinesInRight(chart, mp, shape.divIndex, shape.datas, idx) then
              chart.selectShape := shape.shapeName;
              break
          end;
      end;
      end;
    end;
end;

function SelectPlot(var chart:FCChart; mp:FCPoint):FCPlot;
var
  sPlot:FCPlot;
  i,j:integer;
  plot:FCPlot;
  index1:integer;
  index2:integer;
  index3:integer;
  mpx1:double;
  mpy1:double;
  mpx2:double;
  mpy2:double;
  mpx3:double;
  mpy3:double;
  length:integer;
  newB:double;
  newX1:double;
  newY1:double;
  newX2:double;
  newY2:double;
  leftX:double;
  leftY:double;
  rightX:double;
  rightY:double;
  divHeight:double;
  a:double;
  b:double;
  c:double;
  d:double;
  sX1:double;
  sY1:double;
  sX2:double;
  sY2:double;
  minValue:double;
  maxValue:double;
  ranges:DoubleArray;
  newX:double;
  newY:double;
  r:double;
  roundValue:double;
  x1:double;
  y1:double;
  x2:double;
  y2:double;
  x:double;
  y:double;
  width:double;
  height:double;
  listValue:DoubleArray;
  minIndex:integer;
  maxIndex:integer;
  firstP:FCPoint;
  secondP:FCPoint;
  thirdP:FCPoint;
  startP:FCPoint;
  fK:double;
  fB:double;
  sK:double;
  sB:double;
  newYF:double;
  newYS:double;
  listP:array of FCPoint;
  fValue:integer;
  aIndex:integer;
  pos:integer;
  newIndex:integer;
begin
  sPlot := FCPlot.Create();
  sPlot.uid := -1;
  sPlot.isNotEmpty := false;
  chart.startMovePlot := false;
	chart.selectPlotPoint := -1;
  i := 0;
  j := 0;
  index1 := 0;
  index2 := 0;
  index3 := 0;
  mpx1 := 0;
  mpy1 := 0;
  mpx2 := 0;
  mpy2 := 0;
  mpx3 := 0;
  mpy3 := 0;
  newB := 0;
  newX1 := 0;
  newY1 := 0;
  newX2 := 0;
  newY2 := 0;
  leftX := 0;
  leftY := 0;
  rightX := 0;
  rightY := 0;
  divHeight := GetCandleDivHeight(chart);
  a := 0;
  b := 0;
  c := 0;
  d := 0;
  sX1 := 0;
  sY1 := 0;
  sX2 := 0;
  sY2 := 0;
  minValue := 0;
  maxValue := 0;
  newX := 0;
  newY := 0;
  r := 0;
  roundValue := 0;
  x1 := 0;
  y1 := 0;
  x2 := 0;
  y2 := 0;
  x := 0;
  y := 0;
  width := 0;
  height := 0;
  minIndex := 0;
  maxIndex := 0;
  fK := 0;
  fB := 0;
  sK := 0;
  sB := 0;
  newYF := 0;
  newYS := 0;
  fValue := 0;
  aIndex := 0;
  pos := 0;
  newIndex := 0;
  SetLength(ranges, 12);
  length := High(chart.plots) - Low(chart.plots) + 1;
  for i := 0 to length - 1 do
  begin
    plot := chart.plots[i];
    index1 := 0;
		index2 := 0;
		index3 := 0;
		mpx1 := 0;
		mpy1 := 0;
		mpx2 := 0;
		mpy2 := 0;
		mpx3 := 0;
		mpy3 := 0;
    if plot.key1 <> 0 then
      begin
			index1 := GetChartIndexByDate(chart, plot.key1);
			mpx1 := GetChartX(chart, index1);
			mpy1 := GetChartY(chart, 0, plot.value1);
			if (mp.x >= mpx1 - chart.plotPointSizeChart) and (mp.x <= mpx1 + chart.plotPointSizeChart) and (mp.y >= mpy1 - chart.plotPointSizeChart) and (mp.y <= mpy1 + chart.plotPointSizeChart) then
        begin
				sPlot := plot;
				chart.selectPlotPoint := 0;
				break;
        end;
      end;
    if plot.key2 <> 0 then
      begin
			index2 := GetChartIndexByDate(chart, plot.key2);
			mpx2 := GetChartX(chart, index2);
			mpy2 := GetChartY(chart, 0, plot.value2);
			if (mp.x >= mpx2 - chart.plotPointSizeChart) and (mp.x <= mpx2 + chart.plotPointSizeChart) and (mp.y >= mpy2 - chart.plotPointSizeChart) and (mp.y <= mpy2 + chart.plotPointSizeChart) then
        begin
				sPlot := plot;
				chart.selectPlotPoint := 1;
				break;
        end;
      end;
    if plot.key3 <> 0 then
      begin
			index3 := GetChartIndexByDate(chart, plot.key3);
			mpx3 := GetChartX(chart, index3);
			mpy3 := GetChartY(chart, 0, plot.value3);
			if (mp.x >= mpx3 - chart.plotPointSizeChart) and (mp.x <= mpx3 + chart.plotPointSizeChart) and (mp.y >= mpy3 - chart.plotPointSizeChart) and (mp.y <= mpy3 + chart.plotPointSizeChart) then
        begin
				sPlot := plot;
				chart.selectPlotPoint := 2;
				break;
        end;
      end;
    if chart.selectPlotPoint = -1 then
      begin
      if plot.plotType = 'Line' then
				chart.startMovePlot := SelectLine(chart, mp, mpx1, mpy1, mpx2, mpy2)
			else if plot.plotType = 'ArrowSegment' then
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
			else if plot.plotType = 'AngleLine' then
        begin
				chart.startMovePlot := SelectLine(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectLine(chart, mp, mpx1, mpy1, mpx3, mpy3);
        end
      else if plot.plotType = 'Parallel' then
        begin
				chart.startMovePlot := SelectLine(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
          begin
					LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
					newB := mpy3 - chart.kChart * mpx3;
					if mpx2 = mpx1 then
            begin
						if (mp.x >= mpx3 - chart.plotPointSizeChart) and (mp.x <= mpx3 + chart.plotPointSizeChart) then
							chart.startMovePlot := true;
            end
					else
            begin
						newX1 := chart.leftVScaleWidth;
						newY1 := newX1 * chart.kChart + newB;
						newX2 := chart.size.cx - chart.rightVScaleWidth;
						newY2 := newX2 * chart.kChart + newB;
						chart.startMovePlot := SelectLine(chart, mp, newX1, newY1, newX2, newY2);
            end;
          end;
        end
      else if plot.plotType = 'LRLine' then
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
			else if plot.plotType = 'Segment' then
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
			else if plot.plotType = 'Ray' then
				chart.startMovePlot := SelectRay(chart, mp, mpx1, mpy1, mpx2, mpy2)
      else if plot.plotType = 'Triangle' then
        begin
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, mpx2, mpy2, mpx3, mpy3);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx3, mpy3);
        end
      else if plot.plotType = 'SymmetricTriangle' then
        begin
				if mpx2 <> mpx1 then
          begin
					a := (mpy2 - mpy1) / (mpx2 - mpx1);
					b := mpy1 - a * mpx1;
					c := -a;
					d := mpy3 - c * mpx3;
					leftX := chart.leftVScaleWidth;
					leftY := leftX * a + b;
					rightX := chart.size.cx - chart.rightVScaleWidth;
					rightY := rightX * a + b;
					chart.startMovePlot := SelectSegment(chart, mp, leftX, leftY, rightX, rightY);
					if chart.startMovePlot = false then
            begin
						leftY := leftX * c + d;
						rightY := rightX * c + d;
						chart.startMovePlot := SelectSegment(chart, mp, leftX, leftY, rightX, rightY);
            end;
          end
				else
          begin
					divHeight := getCandleDivHeight(chart);
					chart.startMovePlot := SelectSegment(chart, mp, mpx1, 0, mpx1, divHeight);
					if chart.startMovePlot = false then	
						chart.startMovePlot := SelectSegment(chart, mp, mpx3, 0, mpx3, divHeight);
          end;
        end
      else if plot.plotType = 'Rect' then
        begin
        if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				chart.startMovePlot := SelectSegment(chart, mp, sX1, sY1, sX2, sY1);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX2, sY1, sX2, sY2);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX1, sY2, sX2, sY2);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX1, sY1, sX1, sY2);
        end
      else if plot.plotType = 'BoxLine' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				chart.startMovePlot := SelectSegment(chart, mp, sX1, sY1, sX2, sY1);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX2, sY1, sX2, sY2);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX1, sY2, sX2, sY2);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX1, sY1, sX1, sY2);
        end
      else if plot.plotType = 'TironeLevels' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				chart.startMovePlot := SelectSegment(chart, mp, sX1, sY1, sX2, sY1);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX1, sY2, sX2, sY2);
        end
      else if plot.plotType = 'QuadrantLines' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				chart.startMovePlot := SelectSegment(chart, mp, sX1, sY1, sX2, sY1);
				if chart.startMovePlot = false then
					chart.startMovePlot := SelectSegment(chart, mp, sX1, sY2, sX2, sY2);
        end
      else if plot.plotType = 'GoldenRatio' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				ranges[0] := 0;
				ranges[1] := 0.236;
				ranges[2] := 0.382;
				ranges[3] := 0.5;
				ranges[4] := 0.618;
				ranges[5] := 0.809;
				ranges[6] := 1;
				ranges[7] := 1.382;
				ranges[8] := 1.618;
				ranges[9] := 2;
				ranges[10] := 2.382;
				ranges[11] := 2.618;
        if plot.value1 > plot.value2 then
          minValue := plot.value2
        else
          minValue := plot.value1;
        if plot.value1 > plot.value2 then
          maxValue := plot.value1
        else
          maxValue := plot.value2;
        for j := 0 to 11 do
        begin
          newY := sY2 + (sY1 - sY2) * (1 - ranges[j]);
					if sY1 <= sY2 then
						newY := sY1 + (sY2 - sY1) * ranges[j];
					chart.startMovePlot := SelectSegment(chart, mp, chart.leftVScaleWidth, newY, chart.size.cx - chart.rightVScaleWidth, newY);
					if chart.startMovePlot then
						break
        end;
        end
      else if plot.plotType = 'Cycle' then
        begin
				r := Sqrt((mpx2 - mpx1) * (mpx2 - mpx1) + Abs((mpy2 - mpy1) * (mpy2 - mpy1)));
				roundValue := (mp.x - mpx1) * (mp.x - mpx1) + (mp.y - mpy1) * (mp.y - mpy1);
				if (roundValue / (r * r) >= 0.9) and (roundValue / (r * r) <= 1.1) then
					chart.startMovePlot := true;
        end
      else if plot.plotType = 'CircumCycle' then
        begin
				EllipseOR(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3);
				roundValue := (mp.x - chart.oXChart) * (mp.x - chart.oXChart) + (mp.y - chart.oYChart) * (mp.y - chart.oYChart);
				if (roundValue / (chart.rChart * chart.rChart) >= 0.9) and (roundValue / (chart.rChart * chart.rChart) <= 1.1) then
					chart.startMovePlot := true;
        end
      else if plot.plotType = 'Ellipse' then
        begin
				x1 := 0;
				y1 := 0;
				x2 := 0;
				y2 := 0;
				if mpx1 <= mpx2 then
          begin
					x1 := mpx2;
					y1 := mpy2;
					x2 := mpx1;
					y2 := mpy1;
          end
				else
					x1 := mpx1;
					y1 := mpy1;
					x2 := mpx2;
					y2 := mpy2;
				x := x1 - (x1 - x2);
				y := 0;
				width := (x1 - x2) * 2;
				height := 0;
				if y1 >= y2 then
					height := (y1 - y2) * 2
				else
					height := (y2 - y1) * 2;
				y := y2 - height / 2;
				a := width / 2;
				b := height / 2;
				chart.startMovePlot := EllipseHasPoint(mp.x, mp.y, x + (width / 2), y + (height / 2), a, b);
        end
      else if plot.plotType = 'LRBand' then
        begin
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
          begin
          if index1 <> index2 then
            begin
            if index1 < index2 then
              begin
              minIndex := index1;
              maxIndex := index2;
              end
            else
              begin
              minIndex := index2;
              maxIndex := index1;
              end;
            SetLength(listValue, maxIndex - minIndex + 1);
            for j := minIndex to maxIndex do
            begin
              listValue[j - minIndex] := chart.data[j].close;
            end;
            LinearRegressionEquation(chart, listValue);
            GetLRBandRange(chart, plot, chart.kChart, chart.bChart);
            mpy1 := GetChartY(chart, 0, plot.value1 + chart.upSubValue);
            mpy2 := GetChartY(chart, 0, plot.value2 + chart.upSubValue);
            chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
            if chart.startMovePlot = false then
              begin
              mpy1 := GetChartY(chart, 0, plot.value1 - chart.downSubValue);
              mpy2 := GetChartY(chart, 0, plot.value2 - chart.downSubValue);
              chart.startMovePlot := selectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
              end;
            end;
          end;
        end
      else if plot.plotType = 'LRChannel' then
        begin
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				rightX := chart.size.cx - chart.rightVScaleWidth;
				rightY := rightX * chart.kChart + chart.bChart;
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, rightX, rightY);
				if chart.startMovePlot = false then
          begin
          if index1 <> index2 then
            begin
            if index1 < index2 then
              begin
              minIndex := index1;
              maxIndex := index2;
              end
            else
              begin
              minIndex := index2;
              maxIndex := index1;
              end;
            SetLength(listValue, maxIndex - minIndex + 1);
            for j := minIndex to maxIndex do
            begin
              listValue[j - minIndex] := chart.data[j].close;
            end;
            LinearRegressionEquation(chart, listValue);
            GetLRBandRange(chart, plot, chart.kChart, chart.bChart);
            mpy1 := GetChartY(chart, 0, plot.value1 + chart.upSubValue);
            mpy2 := GetChartY(chart, 0, plot.value2 + chart.upSubValue);
            LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
            rightY := rightX * chart.kChart + chart.bChart;
            chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, rightX, rightY);
            if chart.startMovePlot = false then
              begin
              mpy1 := GetChartY(chart, 0, plot.value1 - chart.downSubValue);
              mpy2 := GetChartY(chart, 0, plot.value2 - chart.downSubValue);
              LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
              rightY := rightX * chart.kChart + chart.bChart;
              chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, rightX, rightY);
              end;
            end;
          end;
        end
      else if plot.plotType = 'ParalleGram' then
        begin
				Parallelogram(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3);
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
          begin
					chart.startMovePlot := SelectSegment(chart, mp, mpx2, mpy2, mpx3, mpy3);
					if chart.startMovePlot = false then
            begin
						chart.startMovePlot := SelectSegment(chart, mp, mpx3, mpy3, chart.x4Chart, chart.y4Chart);
						if chart.startMovePlot = false then
							chart.startMovePlot := SelectSegment(chart, mp, chart.x4Chart, chart.y4Chart, mpx1, mpy1);
            end;
          end;
        end
      else if plot.plotType = 'SpeedResist' then
        begin
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
          begin
					if (mpx1 <> mpx2) and (mpy1 <> mpy2) then
            begin
						firstP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) / 3);
						secondP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 2 / 3);
						startP := FCPoint.Create(mpx1, mpy1);
						fK := 0;
						fB := 0;
						sK := 0;
						sB := 0;
						LineXY(chart, startP.x, startP.y, firstP.x, firstP.y, 0, 0);
						fK := chart.kChart;
						fB := chart.bChart;
						LineXY(chart, startP.x, startP.y, secondP.x, secondP.y, 0, 0);
						sK := chart.kChart;
						sB := chart.bChart;
						newYF := 0;
						newYS := 0;
						newX := 0;
						if mpx2 > mpx1 then
              begin
							newYF := fK * (chart.size.cx - chart.rightVScaleWidth) + fB;
							newYS := sK * (chart.size.cx - chart.rightVScaleWidth) + sB;
							newX := (chart.size.cx - chart.rightVScaleWidth);
              end
						else
              begin
							newYF := fB;
							newYS := sB;
							newX := chart.leftVScaleWidth;
              end;
						chart.startMovePlot := SelectSegment(chart, mp, startP.x, startP.y, newX, newYF);
						if chart.startMovePlot = false then
							chart.startMovePlot := SelectSegment(chart, mp, startP.x, startP.y, newX, newYS);
            end;
          end;
        end
      else if plot.plotType = 'FiboFanline' then
        begin
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2);
				if chart.startMovePlot = false then
          begin
					if (mpx1 <> mpx2) and (mpy1 <> mpy2) then
            begin
						firstP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 0.382);
						secondP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 0.5);
						thirdP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 0.618);
						startP := FCPoint.Create(mpx1, mpy1);
            SetLength(listP, 3);
						listP[0] := firstP;
            listP[1] := secondP;
            listP[2] := thirdP;
            for j := 0 to 2 do
            begin
              LineXY(chart, startP.x, startP.y, listP[j].x, listP[j].y, 0, 0);
							newX := 0;
							newY := 0;
							if mpx2 > mpx1 then
                begin
								newY := chart.kChart * (chart.size.cx - chart.rightVScaleWidth) + chart.bChart;
								newX := (chart.size.cx - chart.rightVScaleWidth);
                end
							else
                begin
								newY := chart.bChart;
								newX := chart.leftVScaleWidth;
                end;
							chart.startMovePlot := SelectSegment(chart, mp, startP.x, startP.y, newX, newY);
							if chart.startMovePlot then
								break;
              end;
            end;
          end;
        end
      else if plot.plotType = 'FiboTimezone' then
        begin
				fValue := 1;
				aIndex := index1;
				pos := 1;
				divHeight := GetCandleDivHeight(chart);
				chart.startMovePlot := SelectSegment(chart, mp, mpx1, 0, mpx1, divHeight);
				if chart.startMovePlot = false then
          begin
					while aIndex + fValue <= chart.lastVisibleIndex do
          begin
						fValue := FibonacciValue(pos);
						newIndex := aIndex + fValue;
						newX := GetChartX(chart, newIndex);
						chart.startMovePlot := SelectSegment(chart, mp, newX, 0, newX, divHeight);
						if chart.startMovePlot then
							break;
						pos := pos + 1;
					end;
          end;
        end
      else if plot.plotType = 'Percent' then
        begin
				GetPercentParams(mpy1, mpy2, listValue);
        for j := 0 to 4 do
        begin
          chart.startMovePlot := SelectSegment(chart, mp, chart.leftVScaleWidth, listValue[j], chart.size.cx - chart.rightVScaleWidth, listValue[j]);
					if chart.startMovePlot then
						break;
        end;
        end;
      if chart.startMovePlot then
        begin
				sPlot := plot;
				sPlot.startKey1 := plot.key1;
				sPlot.startValue1 := plot.value1;
				sPlot.startKey2 := plot.key2;
				sPlot.startValue2 := plot.value2;
				sPlot.startKey3 := plot.key3;
				sPlot.startValue3 := plot.value3;
				break
        end;
      end;
  end;
  SelectPlot := sPlot;
end; 

procedure DrawChartScale(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);
var
  candleDivHeight, volDivHeight, indDivHeight:double;
  dataCount:integer;
  topPoint:FCPoint;
  bottomPoint:FCPoint;
  candleMax:double;
  candleMin:double;
  drawValues:DoubleArray;
  drawValuesLength:integer;
  isTrend:boolean;
  firstOpen:double;
  subValue:double;
  count:integer;
  pos:integer;
  start:double;
  i:integer;
  hAxisY:double;
  drawText:string;
  tSize:FCSize;
  diffRange:double;
  diffRangeStr:string;
  volMax:double;
  volMin:double;
  indMax:double;
  indMin:double;
  dLeft:double;
  xText:string;
  x:double;
  dx:double;
begin
  dataCount := High(chart.data) - Low(chart.data) + 1;
  candleDivHeight := GetCandleDivHeight(chart);
  volDivHeight := GetVolDivHeight(chart);
  indDivHeight := GetIndDivHeight(chart);
  candleMax := 0;
  candleMin := 0;
  drawValuesLength := 0;
  isTrend := false;
  firstOpen := 0;
  subValue := 0;
  count := 0;
  pos := 0;
  start := 0;
  i := 0;
  hAxisY := 0;
  diffRange := 0;
  volMax := 0;
  volMin := 0;
  indMax := 0;
  indMin := 0;
  dLeft := 0;
  SetLength(drawValues, 10000);
  if chart.leftVScaleWidth > 0 then
		paint.FillRect(chart.scaleColor, chart.leftVScaleWidth, 0, chart.leftVScaleWidth + chart.lineWidthChart, chart.size.cy - chart.hScaleHeight);
	if chart.rightVScaleWidth > 0 then
		paint.FillRect(chart.scaleColor, chart.size.cx - chart.rightVScaleWidth, 0, chart.size.cx - chart.rightVScaleWidth + chart.lineWidthChart, chart.size.cy - chart.hScaleHeight);
	if chart.hScaleHeight > 0 then
		paint.FillRect(chart.scaleColor, 0, chart.size.cy - chart.hScaleHeight, chart.size.cx, chart.size.cy - chart.hScaleHeight + chart.lineWidthChart);
  if volDivHeight > 0 then
		paint.FillRect(chart.scaleColor, chart.leftVScaleWidth, candleDivHeight, chart.size.cx - chart.rightVScaleWidth, candleDivHeight + chart.lineWidthChart);
	if indDivHeight > 0 then
		paint.FillRect(chart.scaleColor, chart.leftVScaleWidth, candleDivHeight + volDivHeight, chart.size.cx - chart.rightVScaleWidth, candleDivHeight + volDivHeight + chart.lineWidthChart);
  if dataCount > 0 then
    begin
    topPoint := FCPoint.Create(0, 20);
		bottomPoint := FCPoint.Create(0, candleDivHeight - 10);
		candleMax := GetChartValue(chart, topPoint);
		candleMin := GetChartValue(chart, bottomPoint);
    ChartGridScale(chart, candleMin, candleMax, (candleDivHeight - chart.candlePaddingTop - chart.candlePaddingBottom) / 2, chart.vScaleDistance, chart.vScaleDistance / 2, trunc((candleDivHeight - chart.candlePaddingTop - chart.candlePaddingBottom) / chart.vScaleDistance));
    if chart.gridStepChart > 0 then
      begin
      isTrend := false;
			if chart.cycle = 'trend' then
				isTrend := true;
			firstOpen := chart.firstOpen;
      if isTrend then
        begin
        if firstOpen = 0 then
				  firstOpen := chart.data[chart.firstVisibleIndex].close;
				subValue := candleMax - candleMin;
				count := trunc((candleDivHeight - chart.candlePaddingTop - chart.candlePaddingBottom) / chart.vScaleDistance);
        if count > 0 then
					subValue := subValue / count;
        pos := 0;
        start := firstOpen;
				while start < candleMax do
        begin
					start := start + subValue;
					if start <= candleMax then
            begin
						drawValues[pos] := start;
            pos := pos + 1;
            end;
				end;
        start := firstOpen;
				while start > candleMin do
        begin
					start := start - subValue;
					if start >= candleMin then
            begin
						drawValues[pos] := start;
            pos := pos + 1;
            end;
				end;
        end
      else
        begin
        start := 0;
				if candleMin >= 0 then
          begin
					while start + chart.gridStepChart < candleMin do
          begin
						start := start + chart.gridStepChart;
          end;
          end
				else
					while start - chart.gridStepChart > candleMin do
          begin
						start := start - chart.gridStepChart;
					end;
          while start <= candleMax do
          begin
            if start > candleMin then
              begin
              drawValues[pos] := start;
              pos := pos + 1;
              end;
            start := start + chart.gridStepChart;
          end;
        end;
      drawValues[pos] := firstOpen;
      pos := pos + 1;
      for i := 0 to pos - 1 do
      begin
        start := drawValues[i];
        hAxisY := GetChartY(chart, 0, start);
        if (hAxisY < 1) or (hAxisY > candleDivHeight) then
          continue;
        paint.FillRect(chart.gridColor, chart.leftVScaleWidth, hAxisY, chart.size.cx - chart.rightVScaleWidth, hAxisY + chart.lineWidthChart);
        paint.FillRect(chart.scaleColor, chart.leftVScaleWidth - 8, hAxisY, chart.leftVScaleWidth, hAxisY + chart.lineWidthChart);
        paint.FillRect(chart.scaleColor, chart.size.cx - chart.rightVScaleWidth, hAxisY, chart.size.cx - chart.rightVScaleWidth + 8, hAxisY + chart.lineWidthChart);
        drawText := ToFixed(start, chart.candleDigit);
        tSize := paint.textSize(drawText, chart.font);
        if isTrend then
          begin
          diffRange := 100 * (start - firstOpen) / firstOpen;
          diffRangeStr := ToFixed(diffRange, 2) + '%';
          if diffRange >= 0 then
            paint.DrawText(diffRangeStr, chart.upColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2)
          else
            paint.DrawText(diffRangeStr, chart.downColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
          end
        else
          begin
          if chart.vScaleTextColor <> 'none' then
          begin
          paint.DrawText(drawText, chart.vScaleTextColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
          end
          else
          begin
          paint.DrawText(drawText, chart.textColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
          end;
          end;
        if chart.vScaleTextColor <> 'none' then
          begin
        paint.DrawText(drawText, chart.vScaleTextColor, chart.font, chart.leftVScaleWidth - tSize.cx - 10, hAxisY - tSize.cy / 2);
        end
        else
        begin
        paint.DrawText(drawText, chart.textColor, chart.font, chart.leftVScaleWidth - tSize.cx - 10, hAxisY - tSize.cy / 2);
        end;
      end;
    end;
    topPoint := FCPoint.Create(0, candleDivHeight + 10);
		bottomPoint := FCPoint.Create(0, candleDivHeight + volDivHeight - 10);
		volMax := GetChartValue(chart, topPoint);
		volMin := GetChartValue(chart, bottomPoint);
    chartGridScale(chart, volMin, volMax,  (volDivHeight - chart.volPaddingTop - chart.volPaddingBottom) / 2, chart.vScaleDistance, chart.vScaleDistance / 2, trunc((volDivHeight - chart.volPaddingTop - chart.volPaddingBottom) / chart.vScaleDistance));
    if chart.gridStepChart > 0 then
      begin
      start := 0;
			if volMin >= 0 then
        begin
          while start + chart.gridStepChart < volMin do
          begin
            start := start + chart.gridStepChart;
          end;
        end
      else
      begin
        while start - chart.gridStepChart > volMin do
        begin
          start := start - chart.gridStepChart;
        end;
        end;
      while start <= volMax do
      begin
				if start > volMin then
          begin
					hAxisY := GetChartY(chart, 1, start);
					if (hAxisY < candleDivHeight) or (hAxisY > candleDivHeight + volDivHeight) then
          begin
            start := start + chart.gridStepChart;
						continue;
          end;
					paint.FillRect(chart.gridColor, chart.leftVScaleWidth, hAxisY, chart.size.cx - chart.rightVScaleWidth, hAxisY + chart.lineWidthChart);
					paint.FillRect(chart.scaleColor, chart.leftVScaleWidth - 8, hAxisY, chart.leftVScaleWidth, hAxisY + chart.lineWidthChart);
					paint.FillRect(chart.scaleColor, chart.size.cx - chart.rightVScaleWidth, hAxisY, chart.size.cx - chart.rightVScaleWidth + 8, hAxisY + chart.lineWidthChart);
					drawText := toFixed((start / chart.magnitude), chart.volDigit);
					tSize := paint.TextSize(drawText, chart.font);
          if chart.vScaleTextColor <> 'none' then
          begin
					paint.drawText(drawText, chart.vScaleTextColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
					paint.drawText(drawText, chart.vScaleTextColor, chart.font, chart.leftVScaleWidth - tSize.cx - 10, hAxisY - tSize.cy / 2);
          end
          else
          begin
          paint.drawText(drawText, chart.textColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
					paint.drawText(drawText, chart.textColor, chart.font, chart.leftVScaleWidth - tSize.cx - 10, hAxisY - tSize.cy / 2);
          end;
          end;
				start := start + chart.gridStepChart;
			end;
      end;
    if indDivHeight > 0 then
      begin
      topPoint := FCPoint.Create(0, candleDivHeight + volDivHeight + 10);
			bottomPoint := FCPoint.Create(0, candleDivHeight + volDivHeight + indDivHeight - 10);
			indMax := GetChartValue(chart, topPoint);
			indMin := GetChartValue(chart, bottomPoint);
      ChartGridScale(chart, indMin, indMax, (indDivHeight - chart.indPaddingTop - chart.indPaddingBottom) / 2, chart.vScaleDistance, chart.vScaleDistance / 2, trunc((indDivHeight - chart.indPaddingTop - chart.indPaddingBottom) / chart.vScaleDistance));
      if chart.gridStepChart > 0 then
        begin
				start := 0;
				if indMin >= 0 then
          begin
            while start + chart.gridStepChart < indMin do
            begin
              start := start + chart.gridStepChart;
            end;
          end;
        end
      else
        begin
        while start - chart.gridStepChart > indMin do
        begin
          start := start - chart.gridStepChart;
        end;
        end;
      while start <= indMax do
      begin
        if start > indMin then
          begin
          hAxisY := GetChartY(chart, 2, start);
          if (hAxisY < candleDivHeight + volDivHeight) or (hAxisY > candleDivHeight + volDivHeight + indDivHeight) then
          begin
            start := start + chart.gridStepChart;
						continue;
          end;
          paint.FillRect(chart.gridColor, chart.leftVScaleWidth, hAxisY, chart.size.cx - chart.rightVScaleWidth, hAxisY + chart.lineWidthChart);
          paint.FillRect(chart.scaleColor, chart.leftVScaleWidth - 8, hAxisY, chart.leftVScaleWidth, hAxisY + chart.lineWidthChart);
          paint.FillRect(chart.scaleColor, chart.size.cx - chart.rightVScaleWidth, hAxisY, chart.size.cx - chart.rightVScaleWidth + 8, hAxisY + chart.lineWidthChart);
          drawText := ToFixed(start, chart.indDigit);
          tSize := paint.TextSize(drawText, chart.font);
          if chart.vScaleTextColor <> 'none' then
          begin
          paint.DrawText(drawText, chart.vScaleTextColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
          paint.DrawText(drawText, chart.vScaleTextColor, chart.font, chart.leftVScaleWidth - tSize.cx - 10, hAxisY - tSize.cy / 2);
          end
          else
          begin
          paint.DrawText(drawText, chart.textColor, chart.font, chart.size.cx - chart.rightVScaleWidth + 10, hAxisY - tSize.cy / 2);
          paint.DrawText(drawText, chart.textColor, chart.font, chart.leftVScaleWidth - tSize.cx - 10, hAxisY - tSize.cy / 2);
          end;
          end;
        start := start + chart.gridStepChart;
      end;
      end;
    if dataCount > 0 then
      begin
      dLeft := chart.leftVScaleWidth + 10;
			i := chart.firstVisibleIndex;
      while i <= chart.lastVisibleIndex do
      begin
				xText := FloatToStr(chart.data[i].date);
				tSize := paint.TextSize(xText, chart.font);
				x := GetChartX(chart, i);
				dx := x - tSize.cx / 2;
				if (dx > dLeft) and (dx < chart.size.cx - chart.rightVScaleWidth - 10) then
          begin
					paint.DrawLine(chart.scaleColor, chart.lineWidthChart, 0, x, chart.size.cy - chart.hScaleHeight, x, chart.size.cy - chart.hScaleHeight + 8);
          if chart.hScaleTextColor <> 'none' then
          begin
					paint.DrawText(xText, chart.hScaleTextColor, chart.font, dx, chart.size.cy - chart.hScaleHeight + 8  - tSize.cy / 2 + 7);
          end
          else
          begin
          paint.DrawText(xText, chart.textColor, chart.font, dx, chart.size.cy - chart.hScaleHeight + 8  - tSize.cy / 2 + 7);
          end;
					i := i + trunc((tSize.cx + chart.hScaleTextDistance) / chart.hScalePixel) + 1;
          end
				else
					i := i + 1;
      end;
      end;
    end;
end;

procedure DrawChartCrossLine(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);
var
  candleDivHeight, volDivHeight, indDivHeight:double;
  dataCount:integer;
  crossLineIndex:integer;
  drawTitles:array of string;
  drawColors:array of string;
  i:integer;
  pos:integer;
  shapeLength:integer;
  shape:BaseShape;
  iLeft:double;
  tSize:FCSize;
  rightText:string;
  drawX:double;
  drawY:double;
  xText:string;
  xSize:FCSize;
begin
  dataCount := High(chart.data) - Low(chart.data) + 1;
  shapeLength := High(chart.shapes) - Low(chart.shapes) + 1;
  candleDivHeight := GetCandleDivHeight(chart);
  volDivHeight := GetVolDivHeight(chart);
  indDivHeight := GetIndDivHeight(chart);
  crossLineIndex := chart.crossStopIndex;
  i := 0;
  pos := 0;
  iLeft := 0;
  drawX := 0;
  drawY := 0;
  SetLength(drawTitles, 1000);
  SetLength(drawColors, 1000);
	if (crossLineIndex = -1) or (chart.showCrossLine = false) then
  begin
    if chart.lastValidIndex <> -1 then
      crossLineIndex := chart.lastValidIndex
    else
		  crossLineIndex := chart.lastVisibleIndex;
  end;
  if volDivHeight > 0 then
    begin
    if dataCount > 0 then
      begin
			drawTitles[pos] := 'VOL ' + ToFixed(chart.data[crossLineIndex].volume / chart.magnitude, chart.volDigit);
			drawColors[pos] := chart.textColor;
      end
		else
      begin
			drawTitles[pos] := 'VOL';
			drawColors[pos] := chart.textColor;
      end;
    pos := pos + 1;
    if shapeLength > 0 then
      begin
      for i := 0 to shapeLength - 1 do
      begin
        shape := chart.shapes[i];
        if shape.divIndex = 1 then
          begin
					if length(shape.title) > 0 then
						if (shape.shapeType = 'bar') and (shape.style = '2color') then
              begin
							drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.volDigit);
							drawColors[pos] := shape.color2;
              pos := pos + 1;
              end
						else
              begin
							if shape.shapeType <> 'text' then
                begin
								drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.volDigit);
								drawColors[pos] := shape.color;
                pos := pos + 1;
								if length(shape.datas2) > 0 then
                  begin
									drawTitles[pos] := shape.title2 + ' ' + ToFixed(shape.datas2[crossLineIndex], chart.volDigit);
									drawColors[pos] := shape.color2;
                  pos := pos + 1;
                  end;
                end;
              end;
          end;
        end;
      end;
    iLeft := chart.leftVScaleWidth + 5;
		for i := 0 to pos - 1 do
    begin
			tSize := paint.TextSize(drawTitles[i], chart.font);
			paint.DrawText(drawTitles[i], drawColors[i], chart.font, iLeft, candleDivHeight + 5);
			iLeft := iLeft + tSize.cx + 5
		end;
    end;
  pos := 0;
  if chart.cycle = 'trend' then
    begin
    if length(chart.text) > 0 then
    begin
      drawTitles[pos] := chart.text;
      drawColors[pos] := chart.textColor;
      pos := pos + 1;
    end;
    if shapeLength > 0 then
      begin
      for i := 0 to shapeLength - 1 do
      begin
        shape := chart.shapes[i];
        if shape.divIndex = 0 then
          begin
					if length(shape.title) > 0 then
            begin
						if (shape.shapeType = 'bar') and (shape.style = '2color') then
              begin
							drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.candleDigit);
							drawColors[pos] := shape.color2;
              pos := pos + 1;
              end
						else
              begin
							if shape.shapeType <> 'text' then
                begin
								drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.candleDigit);
								drawColors[pos] := shape.color;
                pos := pos + 1;
								if length(shape.datas2) > 0 then
                  begin
									drawTitles[pos] := shape.title2 + ' ' + ToFixed(shape.datas2[crossLineIndex], chart.candleDigit);
									drawColors[pos] := shape.color2;
                  pos := pos + 1;
                  end;
                end;
              end;
            end;
          end;
        end;
      end;
    iLeft := chart.leftVScaleWidth + 5;
		for i := 0 to pos - 1 do
    begin
			tSize := paint.TextSize(drawTitles[i], chart.font);
			paint.DrawText(drawTitles[i], drawColors[i], chart.font, iLeft, 5);
			iLeft := iLeft + tSize.cx + 5;
		end;
    end
  else
  begin
    pos := 0;
    if length(chart.text) > 0 then
    begin
      drawTitles[pos] := chart.text;
      drawColors[pos] := chart.textColor;
      pos := pos + 1;
    end;
    if chart.mainIndicator = 'MA' then
      begin
			if length(chart.ma5) > 0 then
				drawTitles[pos] := 'MA5 ' + ToFixed(chart.ma5[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MA5';
			drawColors[pos] := chart.indicatorColors[0];
      pos := pos + 1;
			if length(chart.ma10) > 0 then
				drawTitles[pos] := 'MA10 ' + ToFixed(chart.ma10[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MA10';
			drawColors[pos] := chart.indicatorColors[1];
      pos := pos + 1;
			if length(chart.ma20) > 0 then
				drawTitles[pos] := 'MA20 ' + ToFixed(chart.ma20[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MA20';
			drawColors[pos] := chart.indicatorColors[2];
      pos := pos + 1;
			if length(chart.ma30) > 0 then
				drawTitles[pos] := 'MA30 ' + ToFixed(chart.ma30[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MA30';
			drawColors[pos] := chart.indicatorColors[5];
      pos := pos + 1;
			if length(chart.ma120) > 0 then
				drawTitles[pos] := 'MA120 ' + ToFixed(chart.ma120[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MA120';
			drawColors[pos] := chart.indicatorColors[4];
      pos := pos + 1;
			if length(chart.ma250) > 0 then
				drawTitles[pos] := 'MA250 ' + ToFixed(chart.ma250[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MA250';
			drawColors[pos] := chart.indicatorColors[3];
      pos := pos + 1;
      end
		else if chart.mainIndicator = 'BOLL' then
      begin
			if length(chart.bollMid) > 0 then
				drawTitles[pos] := 'MID ' + ToFixed(chart.bollMid[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'MID';
			drawColors[pos] := chart.indicatorColors[0];
      pos := pos + 1;
			if length(chart.bollUp) > 0 then
				drawTitles[pos] := 'UP ' + ToFixed(chart.bollUp[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'UP';
			drawColors[pos] := chart.indicatorColors[1];
      pos := pos + 1;
			if length(chart.bollDown) > 0 then
				drawTitles[pos] := 'LOW ' + ToFixed(chart.bollDown[crossLineIndex], chart.candleDigit)
			else
				drawTitles[pos] := 'LOW';
			drawColors[pos] := chart.indicatorColors[2];
      pos := pos + 1;
		  end;
    if shapeLength > 0 then
      begin
      for i := 0 to shapeLength - 1 do
      begin
        shape := chart.shapes[i];
        if shape.divIndex = 0 then
          begin
					if length(shape.title) > 0 then
            begin
						if (shape.shapeType = 'bar') and (shape.style = '2color') then
              begin
							drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.candleDigit);
							drawColors[pos] := shape.color2;
              pos := pos + 1;
              end
						else
              begin
							if shape.shapeType <> 'text' then
                begin
								drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.candleDigit);
								drawColors[pos] := shape.color;
                pos := pos + 1;
								if length(shape.datas2) > 0 then
                  begin
									drawTitles[pos] := shape.title2 + ' ' + ToFixed(shape.datas2[crossLineIndex], chart.candleDigit);
									drawColors[pos] := shape.color2;
                  pos := pos + 1;
                  end;
                end;
              end;
            end;
          end;
      end;
      end;
    iLeft := chart.leftVScaleWidth + 5;
		for i := 0 to pos - 1 do
    begin
			tSize := paint.TextSize(drawTitles[i], chart.font);
			paint.DrawText(drawTitles[i], drawColors[i], chart.font, iLeft, 5);
			iLeft := iLeft + tSize.cx + 5;
		end;
    end;
    if indDivHeight > 0 then
      begin
      pos := 0;
      if chart.showIndicator = 'MACD' then
        begin
        if length(chart.alldifarr) > 0 then 
          drawTitles[pos] := 'DIF ' + ToFixed(chart.alldifarr[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'DIF';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        if length(chart.alldeaarr) > 0 then
          drawTitles[pos] := 'DEA ' + ToFixed(chart.alldeaarr[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'DEA';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        if length(chart.allmacdarr) > 0 then
          drawTitles[pos] := 'MACD ' + ToFixed(chart.allmacdarr[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'MACD';
        drawColors[pos] := chart.indicatorColors[4];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'KDJ' then
        begin
        if length(chart.kdjK) > 0 then
          drawTitles[pos] := 'K ' + ToFixed(chart.kdjK[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'K';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        if length(chart.kdjD) > 0 then
          drawTitles[pos] := 'D ' + ToFixed(chart.kdjD[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'D';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        if length(chart.kdjJ) > 0 then
          drawTitles[pos] := 'J ' + ToFixed(chart.kdjJ[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'J';
        drawColors[pos] := chart.indicatorColors[2];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'RSI' then
        begin
        if length(chart.rsi1) > 0 then
          drawTitles[pos] := 'RSI6 ' + ToFixed(chart.rsi1[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'RSI6';
        drawColors[pos] := chart.indicatorColors[5];
        pos := pos + 1;
        if length(chart.rsi2) > 0 then
          drawTitles[pos] := 'RSI12 ' + ToFixed(chart.rsi2[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'RSI12';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        if length(chart.rsi3) > 0 then
          drawTitles[pos] := 'RSI24 ' + ToFixed(chart.rsi3[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'RSI24';
        drawColors[pos] := chart.indicatorColors[2];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'BIAS' then
        begin
        if length(chart.bias1) > 0 then
          drawTitles[pos] := 'BIAS6 ' + ToFixed(chart.bias1[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'BIAS6';
        drawColors[pos] := chart.indicatorColors[5];
        pos := pos + 1;
        if length(chart.bias2) > 0 then
          drawTitles[pos] := 'BIAS12 ' + ToFixed(chart.bias2[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'BIAS12';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        if length(chart.bias3) > 0 then
          drawTitles[pos] := 'BIAS24 ' + ToFixed(chart.bias3[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'BIAS24';
        drawColors[pos] := chart.indicatorColors[2];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'ROC' then
        begin
        if length(chart.roc) > 0 then
          drawTitles[pos] := 'ROC ' + ToFixed(chart.roc[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'ROC';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        if length(chart.rocMa) > 0 then
          drawTitles[pos] := 'ROCMA ' + ToFixed(chart.rocMa[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'ROCMA';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;   
        end
      else if chart.showIndicator = 'WR' then
        begin
        if length(chart.wr1) > 0 then
          drawTitles[pos] := 'WR5 ' + ToFixed(chart.wr1[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'WR5';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        if length(chart.wr2) > 0 then
          drawTitles[pos] := 'WR10 ' + ToFixed(chart.wr2[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'WR10';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'CCI' then
        begin
        if length(chart.cci) > 0 then
          drawTitles[pos] := 'CCI ' + ToFixed(chart.cci[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'CCI';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'BBI' then
        begin
        if length(chart.bbi) > 0 then
          drawTitles[pos] := 'BBI ' + ToFixed(chart.bbi[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'BBI';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'TRIX' then
        begin
        if length(chart.trix) > 0 then
          drawTitles[pos] := 'TRIX ' + ToFixed(chart.trix[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'TRIX';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        if length(chart.trixMa) > 0 then
          drawTitles[pos] := 'TRIXMA ' + ToFixed(chart.trixMa[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'TRIXMA';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        end
      else if chart.showIndicator = 'DMA' then
        begin
        if length(chart.dma1) > 0 then
          drawTitles[pos] := 'MA10 ' + ToFixed(chart.dma1[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'MA10';
        drawColors[pos] := chart.indicatorColors[0];
        pos := pos + 1;
        if length(chart.dma2) > 0 then
          drawTitles[pos] := 'MA50 ' + ToFixed(chart.dma2[crossLineIndex], chart.indDigit)
        else
          drawTitles[pos] := 'MA50';
        drawColors[pos] := chart.indicatorColors[1];
        pos := pos + 1;
        end;
        if shapeLength > 0 then
          begin
          for i := 0 to shapeLength - 1do
          begin
            shape := chart.shapes[i];
            if shape.divIndex = 2 then
              begin
              if length(shape.title) > 0 then
                begin
                if (shape.shapeType = 'bar') and (shape.style = '2color') then
                  begin
                  drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.indDigit);
                  drawColors[pos] := shape.color2;
                  pos := pos + 1;
                  end
                else
                  begin
                  if shape.shapeType <> 'text' then
                    begin
                    drawTitles[pos] := shape.title + ' ' + ToFixed(shape.datas[crossLineIndex], chart.indDigit);
                    drawColors[pos] := shape.color;
                    pos := pos + 1;
                    if length(shape.datas2) > 0 then
                      begin
                      drawTitles[pos] := shape.title2 + ' ' + ToFixed(shape.datas2[crossLineIndex], chart.indDigit);
                      drawColors[pos] := shape.color2;
                      pos := pos + 1;
                      end;
                    end;
                  end;
                end;
              end;
          end;
          end;
        iLeft := chart.leftVScaleWidth + 5;
        for i := 0 to pos - 1 do
        begin
          tSize := paint.TextSize(drawTitles[i], chart.font);
          paint.DrawText(drawTitles[i], drawColors[i], chart.font, iLeft, candleDivHeight + volDivHeight + 5);
          iLeft := iLeft + tSize.cx + 5;
        end;
      end;
  if (chart.uid = touchDownView.uid) or (chart.uid = touchMoveView.uid) then
    begin
		rightText := '';
		if chart.touchPosition.y < candleDivHeight then
			rightText := ToFixed(GetChartValue(chart, chart.touchPosition), chart.candleDigit)	
		else if (chart.touchPosition.y > candleDivHeight) and (chart.touchPosition.y < candleDivHeight + volDivHeight) then
			rightText := ToFixed(GetChartValue(chart, chart.touchPosition) / chart.magnitude, chart.volDigit)
		else if (chart.touchPosition.y > candleDivHeight + volDivHeight) and (chart.touchPosition.y < candleDivHeight + volDivHeight + indDivHeight) then
			rightText := ToFixed(GetChartValue(chart, chart.touchPosition), chart.indDigit);
		drawY := chart.touchPosition.y;
		if drawY > chart.size.cy - chart.hScaleHeight then
			drawY := chart.size.cy - chart.hScaleHeight;
		tSize := paint.TextSize(rightText, chart.font);
		if chart.leftVScaleWidth > 0 then
      begin
			paint.FillRect(chart.crossTipColor, chart.leftVScaleWidth - tSize.cx, drawY - tSize.cy / 2 - 4, chart.leftVScaleWidth, drawY + tSize.cy / 2 + 3);
			paint.DrawText(rightText, chart.textColor, chart.font, chart.leftVScaleWidth - tSize.cx, drawY - tSize.cy / 2);
      end;
		if chart.rightVScaleWidth > 0 then
      begin
			paint.FillRect(chart.crossTipColor, chart.size.cx - chart.rightVScaleWidth, drawY - tSize.cy / 2 - 4, chart.size.cx - chart.rightVScaleWidth + tSize.cx, drawY + tSize.cy / 2 + 3);
			paint.DrawText(rightText, chart.textColor, chart.font, chart.size.cx - chart.rightVScaleWidth, drawY - tSize.cy / 2);
      end;
		drawX := chart.touchPosition.x;
    if (chart.targetOldX = 0) and (chart.targetOldX2 = 0) then
			drawX := chart.touchPosition.x;
		if drawX < chart.leftVScaleWidth then
			drawX := chart.leftVScaleWidth;
		if drawX > chart.size.cx - chart.rightVScaleWidth then
			drawX := chart.size.cx - chart.rightVScaleWidth;
		if chart.showCrossLine and (chart.sPlot.isNotEmpty = false) and (chart.selectShape = '') then
      begin
			paint.FillRect(chart.crossLineColor, chart.leftVScaleWidth, drawY, chart.size.cx - chart.rightVScaleWidth, drawY + chart.lineWidthChart);
			paint.FillRect(chart.crossLineColor, drawX, 0, drawX + chart.lineWidthChart, chart.size.cy - chart.hScaleHeight);
      end;
		if chart.crossStopIndex <> -1 then
      begin
			xText := '';
			xSize := paint.TextSize(xText, chart.font);
			paint.FillRect(chart.crossTipColor, drawX - xSize.cx / 2 - 2, candleDivHeight + volDivHeight + indDivHeight, drawX + xSize.cx / 2 + 2, candleDivHeight + volDivHeight + indDivHeight + xSize.cy + 6);
			paint.DrawText(xText, chart.textColor, chart.font, drawX - xSize.cx / 2, candleDivHeight + volDivHeight + indDivHeight + 3);
      end;
    end;
end;

procedure DrawChartLines(var chart:FCChart; var paint:FCPaint; clipRect:FCRect; divIndex:integer; datas:DoubleArray; color:String; selected:boolean);
var
  drawPoints:array of FCPoint;
  length:integer;
  maxVisibleRecord:integer;
  lastValidIndex:integer;
  x:double;
  y:double;
  value:double;
  kPInterval:integer;
  pos:integer;
  i:integer;
  fPoint:FCPoint;
begin
  x := 0;
  y := 0;
  value := 0;
  kPInterval := 0;
  pos := 0;
  maxVisibleRecord := GetChartMaxVisibleCount(chart, chart.hScalePixel, GetChartWorkAreaWidth(chart));
	lastValidIndex := chart.lastVisibleIndex;
	if chart.lastValidIndex <> -1 then
		lastValidIndex := chart.lastValidIndex;
  length := lastValidIndex - chart.firstVisibleIndex + 1;
  SetLength(drawPoints, length);
  for i := chart.firstVisibleIndex to lastValidIndex do
  begin
    x := GetChartX(chart, i);
		value := datas[i];
		y := GetChartY(chart, divIndex, value);
		drawPoints[pos] := FCPoint.Create(x, y);
    if selected then
      begin
			kPInterval := trunc(maxVisibleRecord / 30);
			if kPInterval < 2 then
				kPInterval := 3;
			if i mod kPInterval = 0 then
				paint.FillRect(color, x - 3, y - 3, x + 3, y + 3);
      end;
    pos := pos + 1;
  end;
  paint.DrawPolyline(color, chart.lineWidthChart, 0, drawPoints);
end;

procedure DrawChartLinesInRight(var chart:FCChart; var paint:FCPaint; clipRect:FCRect; divIndex:integer; datas:DoubleArray; color:String; selected:boolean);
var
  drawPoints:array of FCPoint;
  length:integer;
  maxVisibleRecord:integer;
  lastValidIndex:integer;
  x:double;
  y:double;
  value:double;
  kPInterval:integer;
  pos:integer;
  i:integer;
  fPoint:FCPoint;
begin
  x := 0;
  y := 0;
  value := 0;
  kPInterval := 0;
  pos := 0;
  maxVisibleRecord := GetChartMaxVisibleCount(chart, chart.hScalePixel, GetChartWorkAreaWidth(chart));
	lastValidIndex := chart.lastVisibleIndex;
	if chart.lastValidIndex <> -1 then
		lastValidIndex := chart.lastValidIndex;
  length := lastValidIndex - chart.firstVisibleIndex + 1;
  SetLength(drawPoints, length);
  for i := chart.firstVisibleIndex to lastValidIndex do
  begin
    x := GetChartX(chart, i);
		value := datas[i];
		y := GetChartYInRight(chart, divIndex, value);
		drawPoints[pos] := FCPoint.Create(x, y);
    if selected then
      begin
			kPInterval := trunc(maxVisibleRecord / 30);
			if kPInterval < 2 then
				kPInterval := 3;
			if i mod kPInterval = 0 then
				paint.FillRect(color, x - 3, y - 3, x + 3, y + 3);
      end;
    pos := pos + 1;
  end;
  paint.DrawPolyline(color, chart.lineWidthChart, 0, drawPoints);
end;

procedure DrawChartPlot(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);
var
  sPlot:FCPlot;
  i,j:integer;
  plot:FCPlot;
  index1:integer;
  index2:integer;
  index3:integer;
  mpx1:double;
  mpy1:double;
  mpx2:double;
  mpy2:double;
  mpx3:double;
  mpy3:double;
  length:integer;
  newB:double;
  newX1:double;
  newY1:double;
  newX2:double;
  newY2:double;
  leftX:double;
  leftY:double;
  rightX:double;
  rightY:double;
  divHeight:double;
  a:double;
  b:double;
  c:double;
  d:double;
  sX1:double;
  sY1:double;
  sX2:double;
  sY2:double;
  minValue:double;
  maxValue:double;
  ranges:DoubleArray;
  newX:double;
  newY:double;
  r:double;
  roundValue:double;
  x1:double;
  y1:double;
  x2:double;
  y2:double;
  x:double;
  y:double;
  width:double;
  height:double;
  listValue:DoubleArray;
  minIndex:integer;
  maxIndex:integer;
  firstP:FCPoint;
  secondP:FCPoint;
  thirdP:FCPoint;
  startP:FCPoint;
  fK:double;
  fB:double;
  sK:double;
  sB:double;
  newYF:double;
  newYS:double;
  listP:array of FCPoint;
  fValue:integer;
  aIndex:integer;
  pos:integer;
  newIndex:integer;
  nHigh:double;
  nLow:double;
  texts:array of string;
  tSize:FCSize;
  bSize:FCSize;
  closeSum:double;
  avgClose:double;
  closeY:double;
  drawAvg:string;
  t1:double;
  t2:double;
  t3:double;
  t4:double;
  t5:double;
  tList:DoubleArray;
  strText:string;
  newPoint:FCPoint;
  value:double;
begin
  sPlot := FCPlot.Create();
  sPlot.isNotEmpty := false;
  i := 0;
  j := 0;
  index1 := 0;
  index2 := 0;
  index3 := 0;
  mpx1 := 0;
  mpy1 := 0;
  mpx2 := 0;
  mpy2 := 0;
  mpx3 := 0;
  mpy3 := 0;
  newB := 0;
  newX1 := 0;
  newY1 := 0;
  newX2 := 0;
  newY2 := 0;
  leftX := 0;
  leftY := 0;
  rightX := 0;
  rightY := 0;
  divHeight := GetCandleDivHeight(chart);
  a := 0;
  b := 0;
  c := 0;
  d := 0;
  sX1 := 0;
  sY1 := 0;
  sX2 := 0;
  sY2 := 0;
  minValue := 0;
  maxValue := 0;
  newX := 0;
  newY := 0;
  r := 0;
  roundValue := 0;
  x1 := 0;
  y1 := 0;
  x2 := 0;
  y2 := 0;
  x := 0;
  y := 0;
  width := 0;
  height := 0;
  minIndex := 0;
  maxIndex := 0;
  fK := 0;
  fB := 0;
  sK := 0;
  sB := 0;
  newYF := 0;
  newYS := 0;
  fValue := 0;
  aIndex := 0;
  pos := 0;
  newIndex := 0;
  nHigh := 0;
  nLow := 0;
  avgClose := 0;
  closeY := 0;
  t1 := 0;
  t2 := 0;
  t3 := 0;
  t4 := 0;
  t5 := 0;
  value := 0;
  SetLength(ranges, 12);
  SetLength(texts, 5);
  length := High(chart.plots) - Low(chart.plots) + 1;
  if length > 0 then
    begin
    paint.SetClip(chart.leftVScaleWidth, 0, chart.size.cx, divHeight);
    for i := 0 to length - 1 do
    begin
      plot := chart.plots[i];
      index1 := 0;
      index2 := 0;
      index3 := 0;
      mpx1 := 0;
      mpy1 := 0;
      mpx2 := 0;
      mpy2 := 0;
      mpx3 := 0;
      mpy3 := 0;
      if (plot.plotType = 'LRLine') or (plot.plotType = 'LRChannel') or (plot.plotType = 'LRBand') then
        begin
				index1 := GetChartIndexByDate(chart, plot.key1);
				index2 := GetChartIndexByDate(chart, plot.key2);
        if index1 <> index2 then
          begin
          if index1 < index2 then
            begin
            minIndex := index1;
            maxIndex := index2;
            end
          else
            begin
            minIndex := index2;
            maxIndex := index1;
            end;
          SetLength(listValue, maxIndex - minIndex + 1);
          for j := minIndex to maxIndex do
          begin
            listValue[j - minIndex] := chart.data[j].close;
          end;
          LinearRegressionEquation(chart, listValue);
          plot.value1 := chart.bChart;
          plot.value2 := chart.kChart * (maxIndex - minIndex + 1) + chart.bChart;
        end;
        end
      else if (plot.plotType = 'BoxLine') or (plot.plotType = 'TironeLevels') or (plot.plotType = 'QuadrantLines') then
        begin
				getCandleRange(chart, plot);
				nHigh := chart.nHighChart;
				nLow := chart.nLowChart;
				index1 := GetChartIndexByDate(chart, plot.key1);
				index2 := GetChartIndexByDate(chart, plot.key2);
        if index1 > index2 then
          begin
          plot.key1 := getChartDateByIndex(chart, index2);
				  plot.key2 := getChartDateByIndex(chart, index1);
          end
        else
          begin
          plot.key1 := getChartDateByIndex(chart, index1);
				  plot.key2 := getChartDateByIndex(chart, index2);
          end;
				plot.value1 := nHigh;
				plot.value2 := nLow;
        end;
      if plot.key1 <> 0 then
        begin
				index1 := GetChartIndexByDate(chart, plot.key1);
				mpx1 := GetChartX(chart, index1);
				mpy1 := GetChartY(chart, 0, plot.value1);
				if chart.sPlot.uid = plot.uid then
					paint.FillEllipse(plot.pointColor, mpx1 - chart.plotPointSizeChart, mpy1 - chart.plotPointSizeChart, mpx1 + chart.plotPointSizeChart, mpy1 + chart.plotPointSizeChart);
        end;
      if plot.key2 <> 0 then
        begin
				index2 := GetChartIndexByDate(chart, plot.key2);
				mpx2 := GetChartX(chart, index2);
				mpy2 := GetChartY(chart, 0, plot.value2);
				if chart.sPlot.uid = plot.uid then
					paint.FillEllipse(plot.pointColor, mpx2 - chart.plotPointSizeChart, mpy2 - chart.plotPointSizeChart, mpx2 + chart.plotPointSizeChart, mpy2 + chart.plotPointSizeChart);
        end;
      if plot.key3 <> 0 then
        begin
				index3 := GetChartIndexByDate(chart, plot.key3);
				mpx3 := GetChartX(chart, index3);
				mpy3 := GetChartY(chart, 0, plot.value3);
				if chart.sPlot.uid = plot.uid then
					paint.FillEllipse(plot.pointColor, mpx3 - chart.plotPointSizeChart, mpy3 - chart.plotPointSizeChart, mpx3 + chart.plotPointSizeChart, mpy3 + chart.plotPointSizeChart);
        end;
      if plot.plotType = 'Line' then
        begin
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				if mpx2 = mpx1 then
          begin
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, 0, mpx1, divHeight)
          end
				else
          begin
					newX1 := chart.leftVScaleWidth;
					newY1 := newX1 * chart.kChart + chart.bChart;
					newX2 := chart.size.cx - chart.rightVScaleWidth;
					newY2 := newX2 * chart.kChart + chart.bChart;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, newX1, newY1, newX2, newY2);
          end;
        end
      else if plot.plotType = 'AngleLine' then
        begin
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				if mpx2 = mpx1 then
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, 0, mpx1, divHeight)
				else
          begin
					newX1 := chart.leftVScaleWidth;
					newY1 := newX1 * chart.kChart + chart.bChart;
					newX2 := chart.size.cx - chart.rightVScaleWidth;
					newY2 := newX2 * chart.kChart + chart.bChart;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, newX1, newY1, newX2, newY2);
          end;
				LineXY(chart, mpx1, mpy1, mpx3, mpy3, 0, 0);
				if mpx3 = mpx1 then
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, 0, mpx1, divHeight)
				else
          begin
					newX1 := chart.leftVScaleWidth;
					newY1 := newX1 * chart.kChart + chart.bChart;
					newX2 := chart.size.cx - chart.rightVScaleWidth;
					newY2 := newX2 * chart.kChart + chart.bChart;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, newX1, newY1, newX2, newY2);
          end;
        end
      else if plot.plotType = 'Parallel' then
        begin
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				if mpx2 = mpx1 then
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, 0, mpx1, divHeight)
				else
          begin
					newX1 := chart.leftVScaleWidth;
					newY1 := newX1 * chart.kChart + chart.bChart;
					newX2 := chart.size.cx - chart.rightVScaleWidth;
					newY2 := newX2 * chart.kChart + chart.bChart;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, newX1, newY1, newX2, newY2);
					newB := mpy3 - chart.kChart * mpx3;
          end;
				if mpx2 = mpx1 then
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx3, 0, mpx3, divHeight)
				else
          begin
					newX1 := chart.leftVScaleWidth;
					newY1 := newX1 * chart.kChart + newB;
					newX2 := chart.size.cx - chart.rightVScaleWidth;
					newY2 := newX2 * chart.kChart + newB;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, newX1, newY1, newX2, newY2);
          end;
				end
      else if plot.plotType = 'Percent' then
        begin
				getPercentParams(mpy1, mpy2, listValue);
        texts[0] := '0%';
        texts[1] := '25%';
        texts[2] := '50%';
        texts[3] := '75%';
        texts[4] := '100%';
        for j := 0 to 4 do
        begin
          paint.DrawLine(plot.lineColor, plot.lineWidth, 0, chart.leftVScaleWidth, listValue[j], chart.size.cx - chart.rightVScaleWidth, listValue[j]);
					tSize := paint.textSize(texts[j], chart.font);
					paint.DrawText(texts[j], chart.textColor, chart.font, chart.leftVScaleWidth + 5, listValue[j] - tSize.cy - 2);
        end;
        end
      else if plot.plotType = 'FiboTimezone' then
        begin
				fValue := 1;
				aIndex := index1;
				pos := 1;
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, 0, mpx1, divHeight);
				tSize := paint.TextSize('1', chart.font);
				paint.DrawText('1', chart.textColor, chart.font, mpx1, divHeight - tSize.cy);
        while aIndex + fValue <= chart.lastVisibleIndex do
        begin
          fValue := FibonacciValue(pos);
          newIndex := aIndex + fValue;
          newX := GetChartX(chart, newIndex);
          paint.DrawLine(plot.lineColor, plot.lineWidth, 0, newX, 0, newX, divHeight);
          tSize := paint.TextSize(ToFixed(fValue, 0), chart.font);
					paint.DrawText(ToFixed(fValue, 0), chart.textColor, chart.font, newX, divHeight - tSize.cy);
          pos := pos + 1;
        end;
        end
      else if plot.plotType = 'SpeedResist' then
        begin
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
				if (mpx1 <> mpx2) and (mpy1 <> mpy2) then
          begin
					firstP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) / 3);
					secondP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 2 / 3);
					startP := FCPoint.Create(mpx1, mpy1);
					fK := 0;
					fB := 0;
					sK := 0;
					sB := 0;
					LineXY(chart, startP.x, startP.y, firstP.x, firstP.y, 0, 0);
					fK := chart.kChart;
					fB := chart.bChart;
					LineXY(chart, startP.x, startP.y, secondP.x, secondP.y, 0, 0);
					sK := chart.kChart;
					sB := chart.bChart;
					newYF := 0;
					newYS := 0;
					newX := 0;
					if mpx2 > mpx1 then
            begin
						newYF := fK * (chart.size.cx - chart.rightVScaleWidth) + fB;
						newYS := sK * (chart.size.cx - chart.rightVScaleWidth) + sB;
						newX := (chart.size.cx - chart.rightVScaleWidth);
            end
					else
            begin
						newYF := fB;
						newYS := sB;
            end;
					newX := chart.leftVScaleWidth;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, startP.x, startP.y, newX, newYF);
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, startP.x, startP.y, newX, newYS);
          end;
        end
      else if plot.plotType = 'FiboFanline' then
        begin
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
				if (mpx1 <> mpx2) and (mpy1 <> mpy2) then
          begin
          firstP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 0.382);
          secondP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 0.5);
          thirdP := FCPoint.Create(mpx2, mpy2 - (mpy2 - mpy1) * 0.618);
          startP := FCPoint.Create(mpx1, mpy1);
          SetLength(listP, 3);
          listP[0] := firstP;
          listP[1] := secondP;
          listP[2] := thirdP;
          for j := 0 to 2 do
          begin
            LineXY(chart, startP.x, startP.y, listP[j].x, listP[j].y, 0, 0);
            newX := 0;
            newY := 0;
            if mpx2 > mpx1 then
              begin
              newY := chart.kChart * (chart.size.cx - chart.rightVScaleWidth) + chart.bChart;
              newX := (chart.size.cx - chart.rightVScaleWidth);
              end
            else
              begin
              newY := chart.bChart;
              newX := chart.leftVScaleWidth;
              end;
            paint.DrawLine(plot.lineColor, plot.lineWidth, 0, startP.x, startP.y, newX, newY);
            end;
          end;
        end
      else if plot.plotType = 'LRLine' then
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2)
			else if plot.plotType = 'LRBand' then
        begin
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
				GetLRBandRange(chart, plot, chart.kChart, chart.bChart);
				mpy1 := GetChartY(chart, 0, plot.value1 + chart.upSubValue);
				mpy2 := GetChartY(chart, 0, plot.value2 + chart.upSubValue);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
				mpy1 := GetChartY(chart, 0, plot.value1 - chart.downSubValue);
				mpy2 := GetChartY(chart, 0, plot.value2 - chart.downSubValue);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
        end
      else if plot.plotType = 'LRChannel' then
        begin
				GetLRBandRange(chart, plot, chart.kChart, chart.bChart);
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				rightX := chart.size.cx - chart.rightVScaleWidth;
				rightY := rightX * chart.kChart + chart.bChart;
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, rightX, rightY);
				mpy1 := GetChartY(chart, 0, plot.value1 + chart.upSubValue);
				mpy2 := GetChartY(chart, 0, plot.value2 + chart.upSubValue);
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				rightY := rightX * chart.kChart + chart.bChart;
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, rightX, rightY);
				mpy1 := GetChartY(chart, 0, plot.value1 - chart.downSubValue);
				mpy2 := GetChartY(chart, 0, plot.value2 - chart.downSubValue);
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				rightY := rightX * chart.kChart + chart.bChart;
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, rightX, rightY);
        end
      else if plot.plotType = 'Segment' then
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2)
			else if plot.plotType = 'Ray' then
        begin
				LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0);
				if (chart.kChart <> 0) or (chart.bChart <> 0) then
          begin
					leftX := chart.leftVScaleWidth;
					leftY := leftX * chart.kChart + chart.bChart;
					rightX := chart.size.cx - chart.rightVScaleWidth;
					rightY := rightX * chart.kChart + chart.bChart;
					if mpx1 >= mpx2 then
						paint.DrawLine(plot.lineColor, plot.lineWidth, 0, leftX, leftY, mpx1, mpy1)
					else
						paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, rightX, rightY);
          end
				else
          begin
					if mpy1 >= mpy2 then
						paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx1, 0)
					else
						paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx1, divHeight);
          end;
        end
      else if plot.plotType = 'Triangle' then
        begin
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx2, mpy2, mpx3, mpy3);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx3, mpy3);
        end
      else if plot.plotType = 'SymmetricTriangle' then
        begin
				if mpx2 <> mpx1 then
          begin
					a := (mpy2 - mpy1) / (mpx2 - mpx1);
					b := mpy1 - a * mpx1;
					c := -a;
					d := mpy3 - c * mpx3;
					leftX := chart.leftVScaleWidth;
					leftY := leftX * a + b;
					rightX := chart.size.cx - chart.rightVScaleWidth;
					rightY := rightX * a + b;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, leftX, leftY, rightX, rightY);
					leftY := leftX * c + d;
					rightY := rightX * c + d;
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, leftX, leftY, rightX, rightY)
          end
				else
          begin
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, 0, mpx1, divHeight);
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx3, 0, mpx3, divHeight);
          end;
        end
      else if plot.plotType = 'Rect' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				paint.DrawRect(plot.lineColor, plot.lineWidth, 0, sX1, sY1, sX2, sY2);
        end
			else if plot.plotType = 'Cycle' then
        begin
				r := Sqrt((mpx2 - mpx1) * (mpx2 - mpx1) + Abs((mpy2 - mpy1) * (mpy2 - mpy1)));
				paint.DrawEllipse(plot.lineColor, plot.lineWidth, 0, mpx1 - r, mpy1 - r, mpx1 + r, mpy1 + r);
        end
      else if plot.plotType = 'CircumCycle' then
        begin
				EllipseOR(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3);
				paint.DrawEllipse(plot.lineColor, plot.lineWidth, 0, chart.oXChart - chart.rChart, chart.oYChart - chart.rChart, chart.oXChart + chart.rChart, chart.oYChart + chart.rChart);
        end
      else if plot.plotType = 'Ellipse' then
        begin
				x1 := 0;
				y1 := 0;
				x2 := 0;
				y2 := 0;
				if mpx1 <= mpx2 then
          begin
					x1 := mpx2;
					y1 := mpy2;
					x2 := mpx1;
					y2 := mpy1;
          end
				else
          begin
					x1 := mpx1;
					y1 := mpy1;
					x2 := mpx2;
					y2 := mpy2;
          end;
				x := x1 - (x1 - x2);
				y := 0;
				width := (x1 - x2) * 2;
				height := 0;
				if y1 >= y2 then
					height := (y1 - y2) * 2
				else
					height := (y2 - y1) * 2;
				y := y2 - height / 2;
				paint.DrawEllipse(plot.lineColor, plot.lineWidth, 0, x, y, x + width, y + height);
        end
      else if plot.plotType = 'ParalleGram' then
        begin
				Parallelogram(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx1, mpy1, mpx2, mpy2);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx2, mpy2, mpx3, mpy3);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, mpx3, mpy3, chart.x4Chart, chart.y4Chart);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, chart.x4Chart, chart.y4Chart, mpx1, mpy1);
        end
      else if plot.plotType = 'BoxLine' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				paint.DrawRect(plot.lineColor, plot.lineWidth, 0, sX1, sY1, sX2, sY2);
				bSize := paint.TextSize('COUNT:' + ToFixed(Abs(index2 - index1) + 1, 0), chart.font);
				paint.DrawText('COUNT:' + ToFixed(Abs(index2 - index1) + 1, 0), chart.textColor, chart.font, sX1 + 2, sY1 + 2);
        closeSum := 0;
        for j := index1 to index2 do
          begin
            closeSum := closeSum +  chart.data[j].close;
          end;
				avgClose := closeSum / (index2 - index1 + 1);
				closeY := GetChartY(chart, 0, avgClose);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 1, sX1, closeY, sX2, closeY);
				drawAvg := 'AVG:' + ToFixed(avgClose, chart.candleDigit);
				tSize := paint.TextSize(drawAvg, chart.font);
				paint.DrawText(drawAvg, chart.textColor, chart.font, sX1 + 2, closeY - tSize.cy - 2);
        end
      else if plot.plotType = 'TironeLevels' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, sX1, sY1, sX2, sY1);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, sX1, sY2, sX2, sY2);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 2, sX1 + (sX2 - sX1) / 2, sY1, sX1 + (sX2 - sX1) / 2, sY2);
				t1 := chart.nHighChart;
				t2 := chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 3;
				t3 := chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 2;
				t4 := chart.nHighChart - 2 * (chart.nHighChart - chart.nLowChart) / 3;
				t5 := chart.nLowChart;
        SetLength(tList, 3);
        tList[0] := t2;
        tList[1] := t3;
        tList[2] := t4;
        for j := 0 to 2 do
          begin
          y := GetChartY(chart, 0, tList[j]);
					paint.DrawLine(plot.lineColor, plot.lineWidth, 2, chart.leftVScaleWidth, y, chart.size.cx - chart.rightVScaleWidth, y);
					strText := ToFixed(tList[j], chart.candleDigit);
					tSize := paint.TextSize(strText, chart.font);
					paint.DrawText(strText, chart.textColor, chart.font, chart.leftVScaleWidth + 2, y - tSize.cy - 2);
          end;
        end
      else if plot.plotType = 'QuadrantLines' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, sX1, sY1, sX2, sY1);
				paint.DrawLine(plot.lineColor, plot.lineWidth, 0, sX1, sY2, sX2, sY2);
				t1 := chart.nHighChart;
				t2 := chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 4;
				t3 := chart.nHighChart - (chart.nHighChart - chart.nLowChart) / 2;
				t4 := chart.nHighChart - 3 * (chart.nHighChart - chart.nLowChart) / 4;
				t5 := chart.nLowChart;
				SetLength(tList, 3);
        tList[0] := t2;
        tList[1] := t3;
        tList[2] := t4;
        for j := 0 to 2 do
        begin
          y := GetChartY(chart, 0, tList[j]);
          paint.DrawLine(plot.lineColor, plot.lineWidth, 0, sX1, y, sX2, y);
        end;
        end
      else if plot.plotType = 'GoldenRatio' then
        begin
				if mpx1 > mpx2 then
          sX1 := mpx2
        else
          sX1 := mpx1;
        if mpy1 > mpy2 then
          sY1 := mpy2
        else
          sY1 := mpy1;
        if mpx1 > mpx2 then
          sX2 := mpx1
        else
          sX2 := mpx2;
        if mpy1 > mpy2 then
          sY2 := mpy1
        else
          sY2 := mpy2;
				ranges[0] := 0;
				ranges[1] := 0.236;
				ranges[2] := 0.382;
				ranges[3] := 0.5;
				ranges[4] := 0.618;
				ranges[5] := 0.809;
				ranges[6] := 1;
				ranges[7] := 1.382;
				ranges[8] := 1.618;
				ranges[9] := 2;
				ranges[10] := 2.382;
				ranges[11] := 2.618;
        if plot.value1 > plot.value2 then
          minValue := plot.value2
        else
          minValue := plot.value1;
        if plot.value1 > plot.value2 then
          maxValue := plot.value1
        else
          maxValue := plot.value2;
        for j := 0 to 11 do
        begin
          newY := sY2 + (sY1 - sY2) * (1 - ranges[j]);
					if sY1 <= sY2 then
						newY := sY1 + (sY2 - sY1) * ranges[j];
					paint.DrawLine(plot.lineColor, plot.lineWidth, 0, chart.leftVScaleWidth, newY, chart.size.cx - chart.rightVScaleWidth, newY);
					newPoint := FCPoint.Create(0, newY);
					value := GetCandleDivValue(chart, newPoint);
					strText := toFixed(value, chart.candleDigit);
					tSize := paint.TextSize(strText, chart.font);
					paint.DrawText(strText, chart.textColor, chart.font, chart.leftVScaleWidth + 2, newY - tSize.cy - 2);
        end;
        end;
      end;
    paint.SetClip(0, 0, chart.size.cx, chart.size.cy);
    end;
end;

procedure DrawChartStock(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);
var
  candleDivHeight, volDivHeight, indDivHeight:double;
  dataCount:integer;
  isTrend:boolean;
  cWidth:double;
  lastValidIndex:integer;
  maxVisibleRecord:integer;
  drawPoints:array of FCPoint;
  i:integer;
  j:integer;
  pos:integer;
  x:double;
  openValue:double;
  closeValue:double;
  highValue:double; 
  lowValue:double; 
  openY:double; 
  closeY:double; 
  highY:double; 
  lowY:double;
  hasMinTag:boolean;
	hasMaxTag:boolean;
  kPInterval:integer;
  tag:string;
  tSize:FCSize;
  volY:double;
  zeroY:double;
  volume:double;
  macd:double;
  macdY:double;
  shapeLength:integer;
  shape:BaseShape;
  y1:double;
  y2:double;
  showHideDatasLength:integer;
  drawText:string;
begin
  shapeLength := High(chart.shapes) - Low(chart.shapes) + 1;
  dataCount := High(chart.data) - Low(chart.data) + 1;
  candleDivHeight := GetCandleDivHeight(chart);
  volDivHeight := GetVolDivHeight(chart);
  indDivHeight := GetIndDivHeight(chart);
  isTrend := false;
  cWidth := 0;
  maxVisibleRecord := 0;
  i := 0;
  j := 0;
  pos := 0;
  x := 0;
  openValue := 0;
  closeValue := 0;
  highValue := 0;
  lowValue := 0;
  openY := 0;
  closeY := 0;
  highY := 0;
  lowY := 0;
  hasMinTag := false;
	hasMaxTag := false;
  kPInterval := 0;
  volY := 0;
  zeroY := 0;
  volume := 0;
  macd := 0;
  macdY := 0;
  y1 := 0;
  y2 := 0;
  showHideDatasLength := 0;
  if dataCount > 0 then
    begin
    isTrend := false;
		if chart.cycle = 'trend' then
			isTrend := true;
		cWidth := trunc((chart.hScalePixel - 3) / 2);
		if cWidth < 0 then
			cWidth := 0;
		lastValidIndex := chart.lastVisibleIndex;
		if chart.lastValidIndex <> -1 then
			lastValidIndex := chart.lastValidIndex;
    maxVisibleRecord := GetChartMaxVisibleCount(chart, chart.hScalePixel, GetChartWorkAreaWidth(chart));
    paint.SetClip(chart.leftVScaleWidth, 0, chart.size.cx, candleDivHeight);
    if isTrend then
      begin
      SetLength(drawPoints, lastValidIndex - chart.firstVisibleIndex + 1);
      for i := chart.firstVisibleIndex to lastValidIndex do
      begin
        x := GetChartX(chart, i);
        closeValue := chart.data[i].close;
        closeY := GetChartY(chart, 0, closeValue);
        drawPoints[pos] := FCPoint.Create(x, closeY);
        pos := pos + 1;
      end;
			paint.DrawPolyline(chart.trendColor, chart.lineWidthChart, 0, drawPoints);
      end
    else
    begin
    for i := chart.firstVisibleIndex to lastValidIndex do
    begin
      x := GetChartX(chart, i);
      openValue := chart.data[i].open;
      closeValue := chart.data[i].close;
      highValue := chart.data[i].high;
      lowValue := chart.data[i].low;
      openY := GetChartY(chart, 0, openValue);
      closeY := GetChartY(chart, 0, closeValue);
      highY := GetChartY(chart, 0, highValue);
      lowY := GetChartY(chart, 0, lowValue);
      if closeValue >= openValue then
        begin
        if (closeValue = openValue) and (chart.midColor <> 'none') then
          begin
            paint.FillRect(chart.midColor, x, highY, x + chart.lineWidthChart, lowY);
          end
          else
          begin
            paint.FillRect(chart.upColor, x, highY, x + chart.lineWidthChart, lowY);
          end;
          if cWidth > 0 then
            begin
            if closeValue = openValue then
            begin
              if chart.midColor <> 'none' then
              begin
                paint.FillRect(chart.midColor, x - cWidth, closeY, x + cWidth, closeY + chart.lineWidthChart);
              end
              else
              begin
                paint.FillRect(chart.upColor, x - cWidth, closeY, x + cWidth, closeY + chart.lineWidthChart);
              end;
            end
            else
            begin
              if chart.candleStyle = 'rect2' then
              begin
                paint.FillRect(chart.backColor, x - cWidth, closeY, x + cWidth + 1, openY);
                paint.DrawRect(chart.upColor, 1, 0, x - cWidth, closeY, x + cWidth + 1, openY);
              end
              else
              begin
                paint.FillRect(chart.upColor, x - cWidth, closeY, x + cWidth + 1, openY);
              end;
            end;
            end;
        end
      else
          begin
          paint.FillRect(chart.downColor, x, highY, x + chart.lineWidthChart, lowY);
          if cWidth > 0 then
            paint.FillRect(chart.downColor, x - cWidth, openY, x + cWidth + 1, closeY);
          end;
      if chart.selectShape = 'CANDLE' then
        begin
        kPInterval := trunc(maxVisibleRecord / 30);
        if kPInterval < 2 then
          kPInterval := 3;
        if i mod kPInterval = 0 then
          paint.FillRect(chart.indicatorColors[0], x - 3, closeY - 3, x + 3, closeY + 3);
        end;
      if hasMaxTag = false then
          begin
          if highValue = chart.candleMax then
            begin
            tag := ToFixed(highValue, chart.candleDigit);
            tSize := paint.TextSize(tag, chart.font);
            paint.DrawText(tag, chart.textColor, chart.font, x - tSize.cx / 2, highY - tSize.cy - 2);
            hasMaxTag := true;
            end;
          end;
        if hasMinTag = false then
          begin
          if lowValue = chart.candleMin then
            begin
            tag := ToFixed(lowValue, chart.candleDigit);
            tSize := paint.TextSize(tag, chart.font);
            paint.DrawText(tag, chart.textColor, chart.font, x - tSize.cx / 2, lowY + 2);
            hasMinTag := true;
            end;
          end;
    end;
    end;
    paint.SetClip(0, 0, chart.size.cx, chart.size.cy);
    if volDivHeight > 0 then
    begin
    for i := chart.firstVisibleIndex to lastValidIndex do
    begin
      x := GetChartX(chart, i);
			openValue := chart.data[i].open;
			closeValue := chart.data[i].close;
			openY := GetChartY(chart, 0, openValue);
			closeY := GetChartY(chart, 0, closeValue);
			volY := 0;
			zeroY := 0;
      volume := chart.data[i].volume;
      volY := GetChartY(chart, 1, volume);
      zeroY := GetChartY(chart, 1, 0);
      if closeValue >= openValue then
        begin
				if isTrend then
          begin
						paint.FillRect(chart.upColor, x, volY, x + chart.lineWidthChart, zeroY);
          end
				else
          begin
					if cWidth > 0 then
            begin
						if chart.barStyle = 'rect2' then
              begin
                paint.FillRect(chart.backColor, x - cWidth, volY, x + cWidth + 1, zeroY);
                paint.DrawRect(chart.upColor, 1, 0, x - cWidth, volY, x + cWidth + 1, zeroY);
              end
              else
              begin
                paint.FillRect(chart.upColor, x - cWidth, volY, x + cWidth + 1, zeroY);
              end;
            end
					else
            begin
						paint.DrawLine(chart.upColor, chart.lineWidthChart, 0, x - cWidth, volY, x + cWidth, zeroY);
            end;
          end;
        end
			else
        begin
				if isTrend then
          begin
					paint.FillRect(chart.downColor, x, volY, x + chart.lineWidthChart, zeroY);
          end
				else
          begin
					if cWidth > 0 then
            begin
						paint.FillRect(chart.downColor, x - cWidth, volY, x + cWidth + 1, zeroY);
            end
					else
            begin
						paint.DrawLine(chart.downColor, chart.lineWidthChart, 0, x - cWidth, volY, x + cWidth, zeroY);
            end;
          end;
        end;
        if chart.selectShape = 'VOL' then
          begin
          kPInterval := trunc(maxVisibleRecord / 30);
          if kPInterval < 2 then
            kPInterval := 3;
          if i mod kPInterval = 0 then
            paint.FillRect(chart.indicatorColors[0], x - 3, volY - 3, x + 3, volY + 3);
          end;
    end;
    end;
    if isTrend = false then
      begin
			paint.SetClip(chart.leftVScaleWidth, 0, chart.size.cx, candleDivHeight);
      if chart.mainIndicator = 'BOLL' then
        begin
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = 'MID') then
					DrawChartLines(chart, paint, clipRect, 0, chart.bollMid, chart.indicatorColors[0], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.bollMid, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = 'UP') then
					DrawChartLines(chart, paint, clipRect, 0, chart.bollUp, chart.indicatorColors[1], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.bollUp, chart.indicatorColors[1], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = 'DOWN') then
					DrawChartLines(chart, paint, clipRect, 0, chart.bollDown, chart.indicatorColors[2], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.bollDown, chart.indicatorColors[2], false);
        end
			else if chart.mainIndicator = 'MA' then
        begin
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = '5') then
					DrawChartLines(chart, paint, clipRect, 0, chart.ma5, chart.indicatorColors[0], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.ma5, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = '10') then
					DrawChartLines(chart, paint, clipRect, 0, chart.ma10, chart.indicatorColors[1], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.ma10, chart.indicatorColors[1], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = '20') then
					DrawChartLines(chart, paint, clipRect, 0, chart.ma20, chart.indicatorColors[2], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.ma20, chart.indicatorColors[2], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = '30') then
					DrawChartLines(chart, paint, clipRect, 0, chart.ma30, chart.indicatorColors[3], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.ma30, chart.indicatorColors[3], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = '120') then
					DrawChartLines(chart, paint, clipRect, 0, chart.ma120, chart.indicatorColors[4], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.ma120, chart.indicatorColors[4], false);
				if (chart.selectShape = chart.mainIndicator) and (chart.selectShapeEx = '250') then
					DrawChartLines(chart, paint, clipRect, 0, chart.ma250, chart.indicatorColors[5], true)
				else
					DrawChartLines(chart, paint, clipRect, 0, chart.ma250, chart.indicatorColors[5], false);
        end;
			paint.SetClip(0, 0, chart.size.cx, chart.size.cy);
      end;
    if indDivHeight > 0 then
      begin
			if chart.showIndicator = 'MACD' then
        begin
				zeroY := GetChartY(chart, 2, 0);
				paint.FillRect(chart.indicatorColors[4], chart.leftVScaleWidth, zeroY, GetChartX(chart, chart.lastVisibleIndex), zeroY + chart.lineWidthChart);
        for i := chart.firstVisibleIndex to lastValidIndex do
        begin
          x := GetChartX(chart, i);
					macd := chart.allmacdarr[i];
					macdY := GetChartY(chart, 2, macd);
					if macdY < zeroY then
						paint.FillRect(chart.indicatorColors[3], x, macdY, x + chart.lineWidthChart, zeroY)
					else
						paint.FillRect(chart.indicatorColors[4], x, zeroY, x + chart.lineWidthChart, macdY);
          if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'MACD') then
            begin
						kPInterval := trunc(maxVisibleRecord / 30);
						if kPInterval < 2 then
							kPInterval := 3;
						if i mod kPInterval = 0 then
							paint.FillRect(chart.indicatorColors[4], x - 3, macdY - 3, x + 3, macdY + 3);
            end;
        end;
        if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'DIF') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.alldifarr, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.alldifarr, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'DEA') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.alldeaarr, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.alldeaarr, chart.indicatorColors[1], false);
        end
      else if chart.showIndicator = 'KDJ' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'K') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.kdjK, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.kdjK, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'D') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.kdjD, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.kdjD, chart.indicatorColors[1], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'J') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.kdjJ, chart.indicatorColors[2], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.kdjJ, chart.indicatorColors[2], false);
        end
			else if chart.showIndicator = 'RSI' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '6') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.rsi1, chart.indicatorColors[5], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.rsi1, chart.indicatorColors[5], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '12') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.rsi2, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.rsi2, chart.indicatorColors[1], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '24') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.rsi3, chart.indicatorColors[2], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.rsi3, chart.indicatorColors[2], false);
        end
			else if chart.showIndicator = 'BIAS' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '1') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.bias1, chart.indicatorColors[5], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.bias1, chart.indicatorColors[5], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '2') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.bias2, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.bias2, chart.indicatorColors[1], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '3') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.bias3, chart.indicatorColors[2], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.bias3, chart.indicatorColors[2], false);
        end
			else if chart.showIndicator = 'ROC' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'ROC') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.roc, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.roc, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'ROCMA') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.rocMa, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.rocMa, chart.indicatorColors[1], false);
        end
			else if chart.showIndicator = 'WR' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '1') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.wr1, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.wr1, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = '2') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.wr2, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.wr2, chart.indicatorColors[1], false);
        end
			else if chart.showIndicator = 'CCI' then
        begin
				if chart.selectShape = chart.showIndicator then
					 DrawChartLines(chart, paint, clipRect, 2, chart.cci, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.cci, chart.indicatorColors[0], false);
        end
			else if chart.showIndicator = 'BBI' then
        begin
				if chart.selectShape = chart.showIndicator then
					 DrawChartLines(chart, paint, clipRect, 2, chart.bbi, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.bbi, chart.indicatorColors[0], false);
        end
			else if chart.showIndicator = 'TRIX' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'TRIX') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.trix, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.trix, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'TRIXMA') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.trixMa, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.trixMa, chart.indicatorColors[1], false);
        end
			else if chart.showIndicator = 'DMA' then
        begin
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'DIF') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.dma1, chart.indicatorColors[0], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.dma1, chart.indicatorColors[0], false);
				if (chart.selectShape = chart.showIndicator) and (chart.selectShapeEx = 'DIFMA') then
					 DrawChartLines(chart, paint, clipRect, 2, chart.dma2, chart.indicatorColors[1], true)
				else
					 DrawChartLines(chart, paint, clipRect, 2, chart.dma2, chart.indicatorColors[1], false);
        end;
      end;
    end;
  if shapeLength > 0 then
    begin
    for i := 0 to shapeLength - 1 do
      begin
        shape := chart.shapes[i];
        if shape.shapeType = 'bar' then
        begin
          for j := chart.firstVisibleIndex to lastValidIndex do
            begin
            showHideDatasLength := High(shape.showHideDatas) - Low(shape.showHideDatas) + 1;
            if (showHideDatasLength > j) and (shape.showHideDatas[j] = 0) then
              continue;
            x := GetChartX(chart, j);
            y1 := 0;
            if shape.leftOrRight then
              y1 := GetChartY(chart, shape.divIndex, shape.datas[j])
            else
              y1 := GetChartYInRight(chart, shape.divIndex, shape.datas[j]);
            if shape.style <> '2color' then
              begin
              y2 := 0;
              if shape.leftOrRight then
                y2 := GetChartY(chart, shape.divIndex, shape.datas2[j])
              else
                y2 := GetChartYInRight(chart, shape.divIndex, shape.datas2[j]);
              if y1 >= y2 then
                paint.FillRect(shape.color, x - cWidth, y2, x + cWidth, y1)
              else
                paint.FillRect(shape.color, x - cWidth, y1, x + cWidth, y2);
              end
            else
              begin
              if shape.leftOrRight then
                begin
                y2 := 0;
                y2 := GetChartY(chart, shape.divIndex, 0);
                end
              else
                y2 := getChartYInRight(chart, shape.divIndex, 0);
              if y1 >= y2 then
                paint.DrawLine(shape.color2, 1, 0, x, y1, x, y2)
              else
                paint.DrawLine(shape.color, 1, 0, x, y1, x, y2);
              if j = lastValidIndex then
                paint.DrawLine(shape.color2, 1, 0, chart.leftVScaleWidth, y2, chart.size.cx - chart.rightVScaleWidth, y2)
              end;
          end;
        end
        else if shape.shapeType = 'text' then
          begin
          for j := chart.firstVisibleIndex to lastValidIndex do
            x := GetChartX(chart, j);
            if shape.datas[j] <> 0 then
              begin
              y1 := 0;
              if shape.leftOrRight then
                y1 := GetChartY(chart, shape.divIndex, shape.value)
              else
                y1 := GetChartYInRight(chart, shape.divIndex, shape.value);
              drawText := shape.text;
              tSize := paint.TextSize(drawText, 'Default,14');
              paint.DrawText(drawText, shape.color, 'Default,14', x - tSize.cx / 2, y1 - tSize.cy / 2);
              end;
          end
        else
          begin
          if shape.leftOrRight then
            begin
            if chart.selectShape = shape.shapeName then
              DrawChartLines(chart, paint, clipRect, shape.divIndex, shape.datas, shape.color, true)
            else
              DrawChartLines(chart, paint, clipRect, shape.divIndex, shape.datas, shape.color, false);
            end
          else
            begin
            if chart.selectShape = shape.shapeName then
              DrawChartLinesInRight(chart, paint, clipRect, shape.divIndex, shape.datas, shape.color, true)
            else
              DrawChartLinesInRight(chart, paint, clipRect, shape.divIndex, shape.datas, shape.color, false);
            end;
          end;
      end;
    end;
end;

procedure DrawChart(var chart:FCChart; var paint:FCPaint; clipRect:FCRect);
begin
  if chart.backColor <> 'none' then
		paint.FillRect(chart.backColor, 0, 0, chart.size.cx, chart.size.cy);
	DrawChartScale(chart, paint, clipRect);
  DrawChartStock(chart, paint, clipRect);
  DrawChartPlot(chart, paint, clipRect);
  DrawChartCrossLine(chart, paint, clipRect);
	if chart.borderColor <> 'none' then
		paint.DrawRect(chart.borderColor, chart.lineWidthChart, 0, 0, 0, chart.size.cx, chart.size.cy);
end;

procedure OnPaintDefault(var inView:FCView; var paint:FCPaint; clipRect:FCRect);
var 
  tSize : FCSize;
  pName:PChar;
begin
  if inView.viewType = 'chart' then
    begin
    DrawChart(FCChart(inView), paint, clipRect);
    end
  else if (inView.viewType = 'div') or (inView.viewType = 'layout') or (inView.viewType = 'tabpage') then
    begin
    DrawDiv(inView, paint, clipRect);
    end
  else if inView.viewType = 'grid' then
    begin
    DrawDiv(inView, paint, clipRect);
    DrawGrid(FCGrid(inView), paint, clipRect);
    end
  else if inView.viewType = 'tree' then
    begin
    DrawDiv(inView, paint, clipRect);
    DrawTree(FCTree(inView), paint, clipRect);
    end
  else if inView.viewType = 'label' then
    begin
      if inView.textColor <> 'none' then
        tSize := paint.TextSize(inView.text, inView.font);
        paint.DrawText(inView.text, inView.textColor, inView.font, 0, (inView.size.cy - tSize.cy) / 2);
    end
  else if inView.exView then
    begin
		pName := PChar(inView.viewName);
		PaintView(paint.gID, pName, 0, 0, trunc(inView.size.cx), trunc(inView.size.cy));
    end
  else if inView.viewType = 'calendar' then
    begin
    DrawCalendar(FCCalendar(inView), paint);
    end
  else if inView.viewType = 'radiobutton' then
    begin
    DrawRadioButton(FCRadioButton(inView), paint, clipRect);
    end
  else if inView.viewType = 'checkbox' then
    begin
    DrawCheckBox(FCCheckBox(inView), paint, clipRect);
    end
  else
    begin
    DrawButton(inView, paint, clipRect);
    end
end;

procedure OnPaintBorderDefault(var inView:FCView; var paint:FCPaint; clipRect:FCRect);
begin
  if inView.viewType = 'grid' then
    begin
    DrawGridScrollBar(FCGrid(inView), paint, clipRect);
    DrawDivBorder(inView, paint, clipRect);
    end
  else if inView.viewType = 'tree' then
    begin
    DrawTreeScrollBar(FCTree(inView), paint, clipRect);
    DrawDivBorder(inView, paint, clipRect);
    end
  else if (inView.viewType = 'div') or (inView.viewType = 'layout') or (inView.viewType = 'tabpage') then
    begin
    DrawDivScrollBar(inView, paint, clipRect);
    DrawDivBorder(inView, paint, clipRect);
    end
  else if inView.viewType = 'textbox' then
    begin
    DrawDivBorder(inView, paint, clipRect);
    end
end;

procedure RenderViews(var views:viewArray; paint:FCPaint; rect:FCRect);
var
  viewsLength:integer;
  i:integer;
  vView:FCView;
  subViews:viewArray;
  subViewsSize:integer;
  clx:double;
  cly:double;
  subView:FCView;
  drawRect:FCRect;
  clipRect:FCRect;
  destRect:FCRect;
  noneRect:FCRect;
begin
  noneRect := FCRect.Create(0, 0, 0, 0);
  viewsLength := High(views) - Low(views) + 1;
  clx := 0;
  cly := 0;
  for i := 0 to viewsLength - 1 do
  begin
    vView := views[i];
    if rect.isNotEmpty = false then
      begin
			subViews := vView.views;
			subViewsSize := High(subViews) - Low(subViews) + 1;
			if subViewsSize > 0 then
        begin
				renderViews(subViews, paint, rect);
        end;
			vView.clipRect := rect;
			continue;
      end;
    if (vView.topMost = false) and IsPaintVisible(vView) then
      begin
      clx := clientX(vView);
			cly := clientY(vView);
      drawRect := FCRect.Create(0, 0, vView.size.cx, vView.size.cy);
			clipRect := FCRect.Create(clx, cly, clx + vView.size.cx, cly + vView.size.cy);
			destRect := FCRect.Create(0, 0, 0, 0);
      if GetIntersectRect(destRect, rect, clipRect) > 0 then
        begin
				vView.clipRect := destRect;
				paint.SetOffset(clx, cly);
				paint.SetClip(destRect.left - clx, destRect.top - cly, destRect.right - clx, destRect.bottom - cly);
        if OnPaintEvent <> nil then
				  OnPaintEvent(vView, paint, rect)
        else
          OnPaintDefault(vView, paint, rect);
				subViews := vView.views;
				subViewsSize := High(subViews) - Low(subViews) + 1;
				if subViewsSize > 0 then
          begin
					renderViews(subViews, paint, destRect);
          end;
				paint.SetOffset(clx, cly);
				paint.SetClip(destRect.left - clx, destRect.top - cly, destRect.right - clx, destRect.bottom - cly);
        if OnPaintBorderEvent <> nil then
				  OnPaintBorderEvent(vView, paint, rect)
        else
          OnPaintBorderDefault(vView, paint, rect);
        end
			else
        begin
				subViews := vView.views;
			  subViewsSize := High(subViews) - Low(subViews) + 1;
        noneRect.isNotEmpty := false;
				if subViewsSize > 0 then
          begin
					RenderViews(subViews, paint, noneRect);
          end;
				vView.clipRect := noneRect;
        end;
      end;
  end;
  for i := 0 to viewsLength - 1 do
  begin
    vView := views[i];
    if rect.isNotEmpty = false then
      begin
			subViews := vView.views;
			subViewsSize := High(subViews) - Low(subViews) + 1;
			if subViewsSize > 0 then
        begin
				renderViews(subViews, paint, rect);
        end;
			vView.clipRect := rect;
			continue;
      end;
    if vView.topMost and IsPaintVisible(vView) then
      begin
      clx := clientX(vView);
			cly := clientY(vView);
      drawRect := FCRect.Create(0, 0, vView.size.cx, vView.size.cy);
			clipRect := FCRect.Create(clx, cly, clx + vView.size.cx, cly + vView.size.cy);
			destRect := FCRect.Create(0, 0, 0, 0);
      if GetIntersectRect(destRect, rect, clipRect) > 0 then
        begin
				vView.clipRect := destRect;
				paint.SetOffset(clx, cly);
				paint.SetClip(destRect.left - clx, destRect.top - cly, destRect.right - clx, destRect.bottom - cly);
				if OnPaintEvent <> nil then
				  OnPaintEvent(vView, paint, rect)
        else
          OnPaintDefault(vView, paint, rect);
				subViews := vView.views;
				subViewsSize := High(subViews) - Low(subViews) + 1;
				if subViewsSize > 0 then
          begin
					renderViews(subViews, paint, destRect);
          end;
				paint.SetOffset(clx, cly);
				paint.SetClip(destRect.left - clx, destRect.top - cly, destRect.right - clx, destRect.bottom - cly);
				if OnPaintBorderEvent <> nil then
				  OnPaintBorderEvent(vView, paint, rect)
        else
          OnPaintBorderDefault(vView, paint, rect);
        end
			else
        begin
				subViews := vView.views;
			  subViewsSize := High(subViews) - Low(subViews) + 1;
        noneRect.isNotEmpty := false;
				if subViewsSize > 0 then
          begin
					RenderViews(subViews, paint, noneRect);
          end;
				vView.clipRect := noneRect;
        end;
      end;
  end;
end;

procedure Invalidate(var paint:FCPaint);
begin
  if paint.hWnd <> 0 then
    begin
    InvalidateViewW32(paint.hWnd, 0, 0, trunc(paint.size.cx), trunc(paint.size.cy))
    end;
end;

procedure InvalidateView(var inView:FCView);
var
  allRect:FCRect;
  drawRect:FCRect;
  clipRect:FCRect;
  clX:double;
  clY:double;
  paint:FCPaint;
begin
  paint := inView.GetPaint();
  if paint.hWnd <> 0 then
    begin
    BeginWmPaint(paint.hWnd);
    clipRect := FCRect.Create(0, 0, 0, 0);
    clipRect.isNotEmpty := false;
    paint.clipRect := clipRect;
    clX := ClientX(inView);
    cly := ClientY(inView);
    allRect := FCRect.Create(0, 0, paint.size.cx / paint.scaleFactorX, paint.size.cy / paint.scaleFactorY);
    drawRect := FCRect.Create(clX, clY, clX + inView.size.cx, clY + inView.size.cy);
    paint.BeginPaint(allRect, drawRect);
    RenderViews(gViews, paint, drawRect);
    paint.EndPaint();
    EndWmPaint(paint.hWnd);
    end;
end;

procedure AutoHideView(mp:FCPoint; paint:FCPaint);
var
  hideView:boolean;
  length:integer;
  i:integer;
  inView:FCView;
  size:FCSize;
  location:FCPoint;
begin
	hideView := false;
  length := High(gViews) - Low(gViews) + 1;
  for i := 0 to length - 1 do
  begin
    inView := gViews[i];
    if inView.autoHide then
      begin
        size := inView.size;
        location := inView.location;
        if (mp.x < location.x) or (mp.x > location.x + size.cx) or (mp.y < location.y) or (mp.y > location.y + size.cy) then
          begin
          if inView.visible then
            begin
            inView.visible := false;
            hideView := true;
            end;
          end;
      end;
  end;
	if hideView then
		Invalidate(paint);
end;

procedure CalendarTimer(var calendar:FCCalendar);
var
  paint:boolean;
begin
  paint := false;
	if calendar.dDiv.aTick > 0 then
    begin
		calendar.dDiv.aTick := trunc(calendar.dDiv.aTick * 2 / 3);
		paint := true;
    end;
	if calendar.mDiv.aTick > 0 then
    begin
		calendar.mDiv.aTick := trunc(calendar.mDiv.aTick * 2 / 3);
		paint := true;
    end;
	if calendar.yDiv.aTick > 0 then
    begin
		calendar.yDiv.aTick := trunc(calendar.yDiv.aTick * 2 / 3);
		paint := true;
    end;
	if paint then
    begin
		UpdateCalendar(calendar);
		InvalidateView(FCView(calendar));
    end;
end;

procedure ClickDayButton(var calendar:FCCalendar; var dButton:DayButton; mp:FCPoint);
var
  lastDay:CDay;
begin
  lastDay := calendar.selectedDay;
	calendar.selectedDay := dButton.day;
	UpdateCalendar(calendar);
  InvalidateView(FCView(calendar)); 
end;

procedure ClickMonthButton(var calendar:FCCalendar; var mButton:MonthButton; mp:FCPoint);
var
  month:CMonth;
  lastDay:CDay;
begin
  month := GetYear(calendar, mButton.year).months[mButton.month];
	calendar.mode := 'day';
	lastDay := calendar.selectedDay;
	calendar.selectedDay := month.days[1];
	UpdateCalendar(calendar);
	InvalidateView(FCView(calendar)); 
end;

procedure ClickYearButton(var calendar:FCCalendar; var yButton:YearButton; mp:FCPoint);
begin
  calendar.mode := 'month';
	SelectYear(calendar, calendar.mDiv, yButton.year);
	UpdateCalendar(calendar);
	InvalidateView(FCView(calendar)); 
end;

procedure ClickLastButton(var calendar:FCCalendar; var hDiv:HeadDiv; mp:FCPoint);
var
  lastMonth:CMonth;
  year:integer;
begin
  if calendar.mode = 'day' then
    begin
		lastMonth := GetLastMonth(calendar, calendar.selectedDay.year, calendar.selectedDay.month);
		calendar.selectedDay := lastMonth.days[1];
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end
	else if calendar.mode = 'month' then
    begin
		year := calendar.mDiv.year;
		year := year - 1;
		SelectYear(calendar, calendar.mDiv, year);
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end
	else if calendar.mode = 'year' then
    begin
		year := calendar.yDiv.startYear;
		year := year - 12;
		SelectStartYear(calendar, calendar.yDiv, year);
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end;
end;

procedure ClickNextButton(var calendar:FCCalendar; var hDiv:HeadDiv; mp:FCPoint);
var
  nextMonth:CMonth;
  lastDay:CDay;
  year:integer;
begin
  if calendar.mode = 'day' then
    begin
		nextMonth := GetNextMonth(calendar, calendar.selectedDay.year, calendar.selectedDay.month);
    calendar.selectedDay := nextMonth.days[1];
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end
	else if calendar.mode = 'month' then
    begin
		year := calendar.mDiv.year;
		year := year + 1;
		SelectYear(calendar, calendar.mDiv, year);
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end
	else if calendar.mode = 'year' then
    begin
		year := calendar.yDiv.startYear;
		year := year + 12;
		SelectStartYear(calendar, calendar.yDiv, year);
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end;
end;

procedure ClickModeButton(var calendar:FCCalendar; var hDiv:HeadDiv; mp:FCPoint);
begin
  if calendar.mode = 'day' then
    begin
		calendar.mode := 'month';
		calendar.mDiv.month := calendar.selectedDay.month;
		calendar.mDiv.year := calendar.selectedDay.year;
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end
	else if calendar.mode = 'month' then
    begin
		calendar.mode := 'year';
		SelectStartYear(calendar, calendar.yDiv, calendar.mDiv.year);
		UpdateCalendar(calendar);
	  InvalidateView(FCView(calendar)); 
    end;
end;

procedure ClickCalendar(var calendar:FCCalendar; mp:FCPoint);
var
  dayButtonsSize:integer;
  monthButtonsSize:integer;
  yearButtonsSize:integer;
  i:integer;
  vDayButton:DayButton;
  vMonthButton:MonthButton;
  vYearButton:YearButton;
  headBounds:FCRect;
  tR:double;
  bounds:FCRect;
begin
  headBounds := calendar.hDiv.bounds;
  if (mp.x >= headBounds.left) and (mp.x <= headBounds.right) and (mp.y >= headBounds.top) and (mp.y <= headBounds.bottom) then
    begin
		tR := 10;
		if mp.x < headBounds.left + tR * 3 then
			clickLastButton(calendar, calendar.hDiv, mp)
		else if mp.x > headBounds.right - tR * 3 then
			clickNextButton(calendar, calendar.hDiv, mp)
		else
			clickModeButton(calendar, calendar.hDiv, mp);
    end;
  if calendar.mode = 'day' then
    begin
		dayButtonsSize := High(calendar.dDiv.dayButtons) - Low(calendar.dDiv.dayButtons) + 1;
    for i := 0 to dayButtonsSize - 1 do 
    begin
      vDayButton := calendar.dDiv.dayButtons[i];
      if vDayButton.visible then
        begin
        bounds := vDayButton.bounds;
        if (mp.x >= bounds.left) and (mp.x <= bounds.right) and (mp.y >= bounds.top) and (mp.y <= bounds.bottom) then
					ClickDayButton(calendar, vDayButton, mp);
        end;
    end;
    end
	else if calendar.mode = 'month' then
    begin
		monthButtonsSize := High(calendar.mDiv.monthButtons) - Low(calendar.mDiv.monthButtons) + 1;
		for i := 0 to monthButtonsSize - 1 do 
    begin
      vMonthButton := calendar.mDiv.monthButtons[i];
      if vMonthButton.visible then
        begin
        bounds := vMonthButton.bounds;
        if (mp.x >= bounds.left) and (mp.x <= bounds.right) and (mp.y >= bounds.top) and (mp.y <= bounds.bottom) then
					ClickMonthButton(calendar, vMonthButton, mp);
        end;
    end;
    end
	else if calendar.mode = 'year' then
    yearButtonsSize := High(calendar.yDiv.yearButtons) - Low(calendar.yDiv.yearButtons) + 1;
		for i := 0 to yearButtonsSize - 1 do 
    begin
      vYearButton := calendar.yDiv.yearButtons[i];
      if vYearButton.visible then
        begin
        bounds := vYearButton.bounds;
        if (mp.x >= bounds.left) and (mp.x <= bounds.right) and (mp.y >= bounds.top) and (mp.y <= bounds.bottom) then
					ClickYearButton(calendar, vYearButton, mp);
        end;
    end;
end;

procedure TouchUpTree(var tree:FCTree; firstTouch:boolean; firstPoint:FCPoint;
    secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
var
  paint:FCPaint;
  cLeft:double;
  cTop:double;
  rowsSize:integer;
  node:FCTreeNode;
  i:integer;
  row:FCTreeRow;
  tLeft:double;
  wLeft:double;
  childNodesLength:integer;
  s:integer;
begin
  paint := tree.GetPaint();
  tree.downScrollHButton := false;
	tree.downScrollVButton := false;
	tree.hoverScrollHButton := false;
	tree.hoverScrollVButton := false;
	cLeft := -tree.scrollH;
	cTop := -tree.scrollV + tree.headerHeight;
  rowsSize := High(tree.rows) - Low(tree.rows) + 1;
  for i := 0 to rowsSize - 1 do
  begin
		row := tree.rows[i];
		if row.visible then
      begin
			if (firstPoint.y >= cTop) and (firstPoint.y <= cTop + tree.rowHeight) then
        begin
				node := row.cells[0];
				tLeft := cLeft + 2 + GetTotalIndent(node);
				wLeft := tLeft;
        for s := 0 to rowsSize - 1 do
        begin
          if s = i then
            begin
            tree.rows[s].selected := true;
            end
          else 
            begin
            tree.rows[s].selected := false;
            end;
        end;
				if tree.showCheckBox then
          begin
					wLeft := wLeft + tree.checkBoxWidth;
					if firstPoint.x < wLeft then
            begin
						if node.checked then
							CheckOrUnCheckTreeNode(node, false)
						else
              begin
							CheckOrUnCheckTreeNode(node, true);
              end;
						InvalidateView(FCView(tree));
						break;
            end;
          end;
        childNodesLength := High(node.childNodes) - Low(node.childNodes) + 1;
				if childNodesLength > 0 then
          begin
					wLeft := wLeft + tree.collapsedWidth;
					if firstPoint.x < wLeft then
            begin
						if node.collapsed then
              begin
							node.collapsed := false;
							HideOrShowTreeNode(tree, node, true);
              end
						else
              begin
							node.collapsed := true;
							HideOrShowTreeNode(tree, node, false);
              end;
						break;
            end;
          end;
        end;
			cTop := cTop + tree.rowHeight;
      end;
	end;
end;

procedure TouchDownChart(var chart:FCChart; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint);
var
  dataCount:integer;
begin
  chart.selectShape := '';
  chart.selectShapeEx := '';
  chart.targetOldX := 0;
	chart.targetOldX2 := 0;
  chart.touchDownPointChart := firstPoint;
  dataCount := High(chart.data) - Low(chart.data) + 1;
  if dataCount > 0 then
    begin
      chart.sPlot := SelectPlot(chart, firstPoint);
      if chart.sPlot.isNotEmpty = false then
      SelectShape(chart, firstPoint);
    end;
  if chart.GetPaint().isDoubleClick then
    begin
    if chart.showCrossLine then
      chart.showCrossLine := false
    else
      chart.showCrossLine := true;
    end;
  InvalidateView(FCView(chart));
end; 

procedure AddPlotDefault(var chart:FCChart; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint);
var
  mp:FCPoint;
  touchIndex:integer;
  fIndex:integer;
  fDate:double;
  y:double;
  newPlot:FCPlot;
  eIndex:integer;
  bIndex:integer;
  sDate:double;
  pLength:integer;
  paint:FCPaint;
begin
  mp := firstPoint;
  pLength := High(chart.plots) - Low(chart.plots) + 1;
  paint := chart.GetPaint();
	if mp.y < GetCandleDivHeight(chart) then
    begin
		touchIndex := GetChartIndex(chart, mp);
		if (touchIndex >= chart.firstVisibleIndex) and (touchIndex <= chart.lastVisibleIndex) then
      begin
			if chart.addingPlotChart = 'FiboTimezone' then
        begin
				fIndex := touchIndex;
				fDate := GetChartDateByIndex(chart, fIndex);
				y := GetCandleDivValue(chart, mp);
				newPlot := FCPlot.Create();
				if paint.defaultUIStyle = 'light' then
          begin
					newPlot.lineColor := 'rgb(0,0,0)';
					newPlot.pointColor := 'rgb(0,0,0)';
          end
				else if paint.defaultUIStyle = 'dark' then
          begin
					newPlot.lineColor := 'rgb(255,255,255)';
					newPlot.pointColor := 'rgb(255,255,255)';
				  end;
				newPlot.key1 := fDate;
				newPlot.value1 := y;
				newPlot.plotType := chart.addingPlotChart;
        SetLength(chart.plots, pLength + 1);
        chart.plots[pLength] :=  newPlot;
				chart.sPlot := SelectPlot(chart, mp);
        end
			else if (chart.addingPlotChart = 'Triangle') or (chart.addingPlotChart = 'CircumCycle') or (chart.addingPlotChart = 'ParalleGram') or (chart.addingPlotChart = 'AngleLine') or (chart.addingPlotChart = 'Parallel') or (chart.addingPlotChart = 'SymmetricTriangle') then
        begin
				eIndex := touchIndex;
				bIndex := eIndex - 5;
				if bIndex >= 0 then
          begin
					fDate := GetChartDateByIndex(chart, bIndex);
					sDate := GetChartDateByIndex(chart, eIndex);
					y := GetCandleDivValue(chart, mp);
					newPlot := FCPlot.Create();
					if paint.defaultUIStyle = 'light' then
            begin
						newPlot.lineColor := 'rgb(0,0,0)';
						newPlot.pointColor := 'rgb(0,0,0)';
            end
					else if paint.defaultUIStyle = 'dark' then
            begin
						newPlot.lineColor := 'rgb(255,255,255)';
						newPlot.pointColor := 'rgb(255,255,255)';
            end;
					newPlot.key1 := fDate;
					newPlot.value1 := y;
					newPlot.key2 := sDate;
					newPlot.value2 := y;
					newPlot.key3 := sDate;
					newPlot.value3 := chart.candleMin + (chart.candleMax - chart.candleMin) / 2;
					newPlot.plotType := chart.addingPlotChart;
					SetLength(chart.plots, pLength + 1);
          chart.plots[pLength] :=  newPlot;
          chart.sPlot := SelectPlot(chart, mp);
          end;
				end
			else
        begin
				eIndex := touchIndex;
				bIndex := eIndex - 5;
				if bIndex >= 0 then
          begin
					fDate := GetChartDateByIndex(chart, bIndex);
					sDate := GetChartDateByIndex(chart, eIndex);
					y := getCandleDivValue(chart, mp);
					newPlot := FCPlot.Create();
					if paint.defaultUIStyle = 'light' then
            begin
						newPlot.lineColor := 'rgb(0,0,0)';
						newPlot.pointColor := 'rgb(0,0,0)';
            end
					else if paint.defaultUIStyle = 'dark' then
            begin
						newPlot.lineColor := 'rgb(255,255,255)';
						newPlot.pointColor := 'rgb(255,255,255)';
					  end;
					newPlot.key1 := fDate;
					newPlot.value1 := y;
					newPlot.key2 := sDate;
					newPlot.value2 := y;
					newPlot.plotType := chart.addingPlotChart;
					SetLength(chart.plots, pLength + 1);
          chart.plots[pLength] := newPlot;
          chart.sPlot := SelectPlot(chart, mp);
          end;
        end;
      end;
    end;
end; 

procedure TouchMoveChart(var chart:FCChart; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint);
var
  dataCount:integer;
  mp:FCPoint;
  newIndex:integer;
  newDate:double;
  newValue:double;
  fPoint:FCPoint;
  sPoint:FCPoint;
  subX:double;
  subIndex:integer;
  newScalePixel:double;
  newFirstIndex:integer;
  thisX:double;
  newSecondIndex:integer;
  maxVisibleRecord:integer;
  bValue:double;
  bIndex:integer;
  startIndex1:integer;
  newIndex1:integer;
  startIndex2:integer;
  newIndex2:integer;
  startIndex3:integer;
  newIndex3:integer;
  intScalePixel:integer;
  fIndex:integer;
  lIndex:integer;
begin
  chart.targetOldX := 0;
	chart.targetOldX2 := 0;
  dataCount := High(chart.data) - Low(chart.data) + 1;
  if dataCount > 0 then
    begin
    mp := firstPoint;
    chart.crossStopIndex := GetChartIndex(chart, mp);
	  chart.touchPosition := mp;
    if firstTouch and chart.sPlot.isNotEmpty then
      begin
		  newIndex := GetChartIndex(chart, mp);
      if (newIndex >= 0) and (newIndex < dataCount) then
        begin
        newDate := GetChartDateByIndex(chart, newIndex);
        newValue := GetCandleDivValue(chart, mp);
        if chart.selectPlotPoint = 0 then
          begin
          chart.sPlot.key1 := newDate;
          chart.sPlot.value1 := newValue;
          end
        else if chart.selectPlotPoint = 1 then
          begin
          chart.sPlot.key2 := newDate;
          chart.sPlot.value2 := newValue;
          end
        else if chart.selectPlotPoint = 2 then
          begin
          chart.sPlot.key3 := newDate;
          chart.sPlot.value3 := newValue;
          end
        else if chart.startMovePlot then
          begin
          bValue := GetCandleDivValue(chart, chart.touchDownPointChart);
          bIndex := GetChartIndex(chart, chart.touchDownPointChart);
          if chart.sPlot.key1 <> 0 then
            begin
            chart.sPlot.value1 := chart.sPlot.startValue1 + (newValue - bValue);
            startIndex1 := GetChartIndexByDate(chart, chart.sPlot.startKey1);
            newIndex1 := startIndex1 + (newIndex - bIndex);
            if newIndex1 < 0 then
              newIndex1 := 0
            else if newIndex1 > dataCount - 1 then
              newIndex1 := dataCount - 1;
            chart.sPlot.key1 := GetChartDateByIndex(chart, newIndex1);
            end;
          if chart.sPlot.key2 <> 0 then
            begin
            chart.sPlot.value2 := chart.sPlot.startValue2 + (newValue - bValue);
            startIndex2 := GetChartIndexByDate(chart, chart.sPlot.startKey2);
            newIndex2 := startIndex2 + (newIndex - bIndex);
            if newIndex2 < 0 then
              newIndex2 := 0
            else if newIndex2 > dataCount - 1 then
              newIndex2 := dataCount - 1;
            chart.sPlot.key2 := GetChartDateByIndex(chart, newIndex2);
            end;
          if chart.sPlot.key3 <> 0 then
            begin
            chart.sPlot.value3 := chart.sPlot.startValue3 + (newValue - bValue);
            startIndex3 := GetChartIndexByDate(chart, chart.sPlot.startKey3);
            newIndex3 := startIndex3 + (newIndex - bIndex);
            if newIndex3 < 0 then
              newIndex3 := 0
            else if newIndex3 > dataCount - 1 then
              newIndex3 := dataCount - 1;
            chart.sPlot.key3 := GetChartDateByIndex(chart, newIndex3);
            end;
          end;
        end;
      end;
      if firstTouch and secondTouch then
        begin
        if firstPoint.x > secondPoint.x then
          begin
          chart.firstTouchPointCacheChart := secondPoint;
          chart.secondTouchPointCacheChart := firstPoint;
          end
        else
          begin
          chart.firstTouchPointCacheChart := firstPoint;
          chart.secondTouchPointCacheChart := secondPoint;
          end;
        if (chart.firstTouchIndexCacheChart = -1) or (chart.secondTouchIndexCacheChart = -1) then
          begin
          chart.firstTouchIndexCacheChart := GetChartIndex(chart, chart.firstTouchPointCacheChart);
          chart.secondTouchIndexCacheChart := GetChartIndex(chart, chart.secondTouchPointCacheChart);
          chart.firstIndexCacheChart := chart.firstVisibleIndex;
          chart.lastIndexCacheChart := chart.lastVisibleIndex;
          end;
        end
      else if firstTouch then
        begin
        chart.secondTouchIndexCacheChart := -1;
        if chart.firstTouchIndexCacheChart = -1 then
          begin
          chart.firstTouchPointCacheChart := firstPoint;
          chart.firstTouchIndexCacheChart := GetChartIndex(chart, chart.firstTouchPointCacheChart);
          chart.firstIndexCacheChart := chart.firstVisibleIndex;
          chart.lastIndexCacheChart := chart.lastVisibleIndex;
          chart.firstPaddingTop := chart.candlePaddingTop;
          chart.firstPaddingBottom := chart.candlePaddingBottom;
          end;
        end;
      if firstTouch and secondTouch then
        begin
        if (chart.firstTouchIndexCacheChart <> -1) and (chart.secondTouchIndexCacheChart <> -1) then
          begin
          fPoint := firstPoint;
          sPoint := secondPoint;
          if firstPoint.x > secondPoint.x then
            begin
            fPoint := secondPoint;
            sPoint := firstPoint;
            end;
          subX := Abs(sPoint.x - fPoint.x);
          subIndex := Abs(chart.secondTouchIndexCacheChart - chart.firstTouchIndexCacheChart);
          if (subX > 0) and (subIndex > 0) then
            begin
            newScalePixel := subX / subIndex;
            if newScalePixel >= 3 then
              begin
              intScalePixel := trunc(newScalePixel);
              newScalePixel := intScalePixel;
              end;
            if newScalePixel <> chart.hScalePixel then
              begin
              newFirstIndex := chart.firstTouchIndexCacheChart;
              thisX := fPoint.x;
              thisX := thisX - newScalePixel;
              while thisX > chart.leftVScaleWidth + newScalePixel do
                begin
                newFirstIndex := newFirstIndex - 1;
                if newFirstIndex < 0 then
                  begin
                  newFirstIndex := 0;
                  break;
                  end;
                thisX := thisX - newScalePixel;
                end;
              thisX := sPoint.x;
              newSecondIndex := chart.secondTouchIndexCacheChart;
              thisX := thisX + newScalePixel;
              while thisX < chart.size.cx - chart.rightVScaleWidth - newScalePixel do
                begin
                newSecondIndex := newSecondIndex + 1;
                if newSecondIndex > dataCount - 1 then
                  begin
                  newSecondIndex := dataCount - 1;
                  break;
                  end;
                thisX := thisX + newScalePixel;
                end;
              SetChartVisibleIndex(chart, newFirstIndex, newSecondIndex);
              maxVisibleRecord := GetChartMaxVisibleCount(chart, chart.hScalePixel, GetChartWorkAreaWidth(chart));
              while (maxVisibleRecord < chart.lastVisibleIndex - chart.firstVisibleIndex + 1) and (chart.lastVisibleIndex > chart.firstVisibleIndex) do
              begin
                chart.lastVisibleIndex := chart.lastVisibleIndex - 1;
              end;
              CheckChartLastVisibleIndex(chart);
              ResetChartVisibleRecord(chart);
              CalculateChartMaxMin(chart);
            end;
          end;
        end;
        end
      else if firstTouch then
        begin
        if chart.autoFillHScale = False then
        begin
          subIndex := trunc((chart.firstTouchPointCacheChart.x - firstPoint.x) / chart.hScalePixel);
          if chart.allowDragChartDiv then
            begin
            chart.candlePaddingTop := chart.firstPaddingTop - trunc(chart.firstTouchPointCacheChart.y - firstPoint.y);
            chart.candlePaddingBottom := chart.firstPaddingBottom + trunc(chart.firstTouchPointCacheChart.y - firstPoint.y);
            end;
          fIndex := chart.firstIndexCacheChart + subIndex;
          lIndex := chart.lastIndexCacheChart + subIndex;
          if fIndex > dataCount - 1 then
          begin
            fIndex := dataCount - 1;
            lIndex := dataCount - 1;
          end;
          chart.firstVisibleIndex := fIndex;
          chart.lastVisibleIndex := lIndex;
          CheckChartLastVisibleIndex(chart);
          ResetChartVisibleRecord(chart);
          CalculateChartMaxMin(chart);
          end;
        end;
  end;
end;

procedure OnMouseDownDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);
var
  firstTouch:boolean;
	secondTouch:boolean;
	firstPoint:FCPoint;
	secondPoint:FCPoint;
  chart:FCChart;
begin
  firstPoint := mp;
	secondPoint := mp;
	if buttons = 1 then
		firstTouch := true
	else if buttons = 2 then
		secondTouch := true;
  if inView.viewType = 'grid' then
    begin
		TouchDownGrid(FCGrid(inView), firstTouch, firstPoint, secondTouch, secondPoint, clicks);
		InvalidateView(inView);
    end
	else if inView.viewType = 'tree' then
    begin
		TouchDownTree(FCTree(inView), firstTouch, firstPoint, secondTouch, secondPoint, clicks);
		InvalidateView(inView);
    end
	else if inView.viewType = 'chart' then
    begin
		TouchDownChart(FCChart(inView), firstTouch, firstPoint, secondTouch, secondPoint);
		end
	else if (inView.viewType = 'div') or (inView.viewType ='layout') then
    begin
		TouchDownDiv(inView, firstTouch, firstPoint, secondTouch, secondPoint, clicks);
		InvalidateView(inView);
    end
	else if inView.viewType = 'button' then
    begin
		InvalidateView(inView);
    end
	else if inView.viewType = 'calendar' then
    begin
		ClickCalendar(FCCalendar(inView), firstPoint);
	  end
end;

procedure OnMouseUpDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);
var
  firstTouch:boolean;
	secondTouch:boolean;
	firstPoint:FCPoint;
	secondPoint:FCPoint;
  chart:FCChart;
begin
  firstPoint := mp;
	secondPoint := mp;
	if buttons = 1 then
		firstTouch := true
	else if buttons = 2 then
		secondTouch := true;
  if inView.viewType = 'grid' then
    begin
		TouchUpGrid(FCGrid(inView), firstTouch, firstPoint, secondTouch, secondPoint, clicks);
    end
	else if inView.viewType = 'tree' then
    begin
		TouchUpTree(FCTree(inView), firstTouch, firstPoint, secondTouch, secondPoint, clicks);
    end
	else if (inView.viewType = 'div') or (inView.viewType ='layout') then
    begin
		TouchUpDiv(inView, firstTouch, firstPoint, secondTouch, secondPoint, clicks);
    end
	else if inView.viewType = 'chart' then
    begin
        chart := FCChart(inView);
		chart.firstTouchIndexCacheChart := -1;
		chart.secondTouchIndexCacheChart := -1;
    end;
    InvalidateView(inView);
end;

procedure OnMouseMoveDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);
var
  firstTouch:boolean;
	secondTouch:boolean;
	firstPoint:FCPoint;
	secondPoint:FCPoint;
begin
  firstPoint := mp;
	secondPoint := mp;
	if buttons = 1 then
		firstTouch := true
	else if buttons = 2 then
		secondTouch := true;
  if inView.viewType = 'grid' then
    begin
		TouchMoveGrid(FCGrid(inView), firstTouch, firstPoint, secondTouch, secondPoint);
		InvalidateView(inView);
    end
	else if inView.viewType = 'tree' then
    begin
		TouchMoveTree(FCTree(inView), firstTouch, firstPoint, secondTouch, secondPoint);
		InvalidateView(inView);
    end
	else if inView.viewType = 'chart' then
    begin
		TouchMoveChart(FCChart(inView), firstTouch, firstPoint, secondTouch, secondPoint);
		InvalidateView(inView);
    end
	else if (inView.viewType = 'div') or (inView.viewType ='layout') then
    begin
		TouchMoveDiv(inView, firstTouch, firstPoint, secondTouch, secondPoint);
		InvalidateView(inView);
    end
	else if inView.viewType = 'button' then
    begin
		InvalidateView(inView);
    end
  else
    begin
    InvalidateView(inView);
    end;
end;

procedure OnClickDefault(var inView:FCView; firstTouch:boolean; firstPoint:FCPoint; secondTouch:boolean; secondPoint:FCPoint; clicks:integer);
var
  tabView:FCTabView;
  length:integer;
  tabPage:FCTabPage;
  i:integer;
  pView:FCView;
begin
  if inView.viewType = 'radiobutton' then
    begin
		ClickRadioButton(FCRadioButton(inView), firstPoint);
    pView := inView.GetParent();
    if pView.isNotEmpty then
			InvalidateView(pView)
		else
			invalidateView(inView);
    end
	else if inView.viewType = 'checkbox' then
    begin
		ClickCheckBox(FCCheckBox(inView), firstPoint);
		InvalidateView(inView);
    end
	else if inView.viewType = 'tabbutton' then
    begin
    tabView := FCTabView(inView.GetParent());
    length := High(tabView.tabPages) - Low(tabView.tabPages) + 1;
    for i := 0 to length - 1 do
    begin
      tabPage := tabView.tabPages[i];
      if tabPage.headerButton.uid = inView.uid then
        SelectTabPage(tabView, tabPage);
    end;
		InvalidateView(FCView(tabView));
    end;
end;

procedure OnMouseWheelDefault(var inView:FCView; mp:FCPoint; buttons:integer; clicks:integer; delta:integer);
begin
	if inView.viewType = 'grid' then
    begin
		TouchWheelGrid(FCGrid(inView), delta);
		InvalidateView(inView);
    end
	else if inView.viewType = 'tree' then
    begin
		TouchWheelTree(FCTree(inView), delta);
		InvalidateView(inView);
    end
	else if (inView.viewType = 'div') or (inView.viewType ='layout') or (inView.viewType ='menu') then
    begin
		TouchWheelDiv(inView, delta);
		InvalidateView(inView);
    end
	else if inView.viewType = 'chart' then
    begin
		if delta > 0 then
			ZoomOutChart(FCChart(inView))
		else if delta < 0 then
			ZoomInChart(FCChart(inView));
		InvalidateView(inView);
    end;
end;

procedure OnKeyDownDefault(var inView:FCView; value:integer);
begin
	if inView.viewType = 'chart' then
    begin
		if value = 38 then
			ZoomOutChart(FCChart(inView))
		else if value = 40 then
			ZoomInChart(FCChart(inView));
		InvalidateView(inView);
    end;
end;

procedure OnKeyUpDefault(var inView:FCView; value:integer);
begin
end;

procedure OnCharDefault(var inView:FCView; value:integer);
begin
end;

procedure UpdateViewDefault(var views:viewArray);
var
  viewsLength:integer;
  i:integer;
  vView:FCView;
  pView:FCView;
  subViews:viewArray;
  subViewsLength:integer;
  chart:FCChart;
  margin:FCPadding;
  padding:FCPadding;
  vcx:Double;
  vcy:Double;
begin
  viewsLength := High(views) - Low(views) + 1;
  for i := 0 to viewsLength - 1 do
  begin
    vView := views[i];
    pView := vView.GetParent();
    if pView.isNotEmpty and (pView.viewType <> 'split') then
      begin
      margin := vView.margin;
      padding := vView.padding;
      if vView.dock = 'fill' then
        begin
        vcx := pView.size.cx - margin.left - padding.left - margin.right - padding.right;
				if vcx < 0 then
					vcx := 0;
				vcy := pView.size.cy - margin.top - padding.top - margin.bottom - padding.bottom;
				if vcy < 0 then
					vcy := 0;
        vView.location := FCPoint.Create(margin.left + padding.left, margin.top + padding.top);
        vView.size := FCSize.Create(vcx, vcy);
        end
      else if vView.dock = 'left' then
        begin
        vView.location := FCPoint.Create(margin.left + padding.left, margin.top + padding.top);
        vcy := pView.size.cy - margin.top - padding.top - margin.bottom - padding.bottom;
				if vcy < 0 then
					vcy := 0;
        vView.size := FCSize.Create(vView.size.cx, vcy);
        end
      else if vView.dock = 'top' then
        begin
        vView.location := FCPoint.Create(margin.left + padding.left, margin.top + padding.top);
        vcx := pView.size.cx - margin.left - padding.left - margin.right - padding.right;
				if vcx < 0 then
					vcx := 0;
        vView.size := FCSize.Create(vcx, vView.size.cy);
        end
      else if vView.dock = 'right' then
        begin
        vView.location := FCPoint.Create(pView.size.cx - vView.size.cx - padding.right - margin.right, margin.top + padding.top);
        vcy := pView.size.cy - margin.top - padding.top - margin.bottom - padding.bottom;
				if vcy < 0 then
					vcy := 0;
        vView.size := FCSize.Create(vView.size.cx, vcy);
        end
      else if vView.dock = 'bottom' then
        begin
        vView.location := FCPoint.Create(margin.left + padding.left, pView.size.cy - vView.size.cy - margin.bottom - padding.bottom);
        vcx := pView.size.cx - margin.left - padding.left - margin.right - padding.right;
				if vcx < 0 then
					vcx := 0;
        vView.size := FCSize.Create(vcx, vView.size.cy);
        end;
      if vView.align = 'center' then
        vView.location := FCPoint.Create((pView.size.cx - vView.size.cx) / 2, vView.location.y)
      else if vView.align = 'right' then
        vView.location := FCPoint.Create(pView.size.cx - vView.size.cx - padding.right - margin.right, vView.location.y);
      if vView.verticalAlign = 'middle' then
        vView.location := FCPoint.Create(vView.location.x, (pView.size.cy - vView.size.cy) / 2)
      else if vView.verticalAlign = 'bottom' then
        vView.location := FCPoint.Create(vView.location.x, pView.size.cy - vView.size.cy - padding.bottom - margin.bottom)
      end
    else if pView.isNotEmpty = false then
      begin
      if vView.dock = 'fill' then
        vView.size := FCSize.Create(vView.GetPaint().size.cx / vView.GetPaint().scaleFactorX, vView.GetPaint().size.cy / vView.GetPaint().scaleFactorY);
      end;
    if vView.viewType = 'split' then
      ResetSplitLayoutDiv(FCSplitLayoutDiv(vView))
    else if vView.viewType = 'tabview' then
      UpdateTabLayout(FCTabView(vView))
    else if vView.viewType = 'layout' then
      ResetLayoutDiv(FCLayoutDiv(vView))
    else if vView.viewType = 'chart' then
      begin
      chart := FCChart(vView);
      ResetChartVisibleRecord(chart);
      CheckChartLastVisibleIndex(chart);
      CalculateChartMaxMin(chart);
      end
    else if vView.viewType = 'calendar' then
      begin
      UpdateCalendar(FCCalendar(vView));
      end;
    subViews := vView.views;
    subViewsLength := High(subViews) - Low(subViews) + 1;
    if subViewsLength > 0 then
    begin
      if UpdateViewEvent <> nil then
        UpdateViewEvent(subViews)
      else
        UpdateViewDefault(subViews);
    end;
  end;
end;  

procedure WindowResize(var rect:FCRect; resizePoint:integer; nowPoint:FCPoint; startTouchPoint:FCPoint);
begin
  if resizePoint = 0 then
  begin
		rect.left := rect.left + nowPoint.x - startTouchPoint.x;
		rect.top := rect.top + nowPoint.y - startTouchPoint.y;
	end
	else if resizePoint = 1 then
  begin
		rect.left := rect.left + nowPoint.x - startTouchPoint.x;
		rect.bottom := rect.bottom + nowPoint.y - startTouchPoint.y;
	end
	else if resizePoint = 2 then
  begin
		rect.right := rect.right + nowPoint.x - startTouchPoint.x;
		rect.top := rect.top + nowPoint.y - startTouchPoint.y;
	end
	else if resizePoint = 3 then
  begin
		rect.right := rect.right + nowPoint.x - startTouchPoint.x;
		rect.bottom := rect.bottom + nowPoint.y - startTouchPoint.y;
	end
	else if resizePoint = 4 then
  begin
		rect.left := rect.left + nowPoint.x - startTouchPoint.x;
	end
	else if resizePoint = 5 then
  begin
		rect.top := rect.top + nowPoint.y - startTouchPoint.y;
	end
	else if resizePoint = 6 then
  begin
		rect.right := rect.right + nowPoint.x - startTouchPoint.x;
	end
	else if resizePoint = 7 then
  begin
		rect.bottom := rect.bottom + nowPoint.y - startTouchPoint.y;
	end;
end;

function GetResizeState(var inView:FCView; mp:FCPoint):integer;
var
  bWidth:double;
  width:double;
  height:double;
  res:integer;
begin
  bWidth := 5;
  width := inView.size.cx;
  height := inView.size.cy;
  res := -1;
	if (mp.x >= 0) and (mp.x <= bWidth * 2) and (mp.y >= 0) and (mp.y <= bWidth * 2) then
		res := 0
	else if (mp.x >= 0) and (mp.x <= bWidth * 2) and (mp.y >= height - bWidth * 2) and (mp.y <= height) then
		res := 1
	else if (mp.x >= width - bWidth * 2) and (mp.x <= width) and (mp.y >= 0) and (mp.y <= bWidth * 2) then
		res := 2
	else if (mp.x >= width - bWidth * 2) and (mp.x <= width) and (mp.y >= height - bWidth * 2) and (mp.y <= height) then
		res := 3
	else if (mp.x >= 0) and (mp.x <= bWidth) and (mp.y >= 0) and (mp.y <= height) then
		res := 4
	else if (mp.x >= 0) and (mp.x <= width) and (mp.y >= 0) and (mp.y <= bWidth) then
		res := 5
	else if (mp.x >= width - bWidth) and (mp.x <= width) and (mp.y >= 0) and (mp.y <= height) then
		res := 6
	else if (mp.x >= 0) and (mp.x <= width) and (mp.y >= height - bWidth) and (mp.y <= height) then
		res := 7;
  GetResizeState := res;
end;

procedure HandleMouseWheel(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);
var
  inView:FCView;
  cmpPoint:FCPoint;
  pName:PChar;
begin
	inView := FindView(mp, gViews);
	if inView.isNotEmpty then
    begin
		cmpPoint := FCPoint.Create(mp.x - clientX(inView), mp.y - clientY(inView));
    if OnMouseWheelEvent <> nil then
      OnMouseWheelEvent(inView, cmpPoint, buttons, clicks, delta)
    else
      OnMouseWheelDefault(inView, cmpPoint, buttons, clicks, delta);
		if inView.exView then
      begin
			pName := PChar(inView.viewName); 
			MouseWheelView(paint.gID, pName, trunc(cmpPoint.x), trunc(cmpPoint.y), buttons, clicks, delta);
			InvalidateView(inView);
      end;
		end;
end;

procedure HandleMouseDown(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);
var
  lastFocusedView:FCView;
  pName:PChar;
  cmpPoint:FCPoint;
begin
	if clicks = 2 then
		paint.isDoubleClick := true
	else
		paint.isDoubleClick := false;
	paint.cancelClick := false;
	paint.touchDownPoint := mp;
  AutoHideView(paint.touchDownPoint, paint);
  lastFocusedView := focusedView;
  touchDownView := FindView(mp, gViews);
  if touchDownView.isNotEmpty then
    begin
      if focusedView.isNotEmpty and (focusedView.uid <> touchDownView.uid) and focusedView.exView then
        begin
        pName := PChar(focusedView.viewName);
        UnFocusView(paint.gID, pName);
        InvalidateView(focusedView);
        end;
      focusedView := touchDownView;
      cmpPoint := FCPoint.Create(mp.x - ClientX(touchDownView), mp.y - ClientY(touchDownView));
      if OnMouseDownEvent <> nil then
        OnMouseDownEvent(touchDownView, cmpPoint, buttons, clicks, 0)
      else
        OnMouseDownDefault(touchDownView, cmpPoint, buttons, clicks, 0);
      if focusedView.isNotEmpty and focusedView.exView then
        begin
        pName := PChar(focusedView.viewName);
        FocusView(paint.gID, pName);
        MouseDownView(paint.gID, pName, trunc(cmpPoint.x), trunc(cmpPoint.y), buttons, clicks);
        InvalidateView(focusedView);
        end;
      if touchDownView.allowResize then
      begin
        touchDownView.resizePoint := getResizeState(touchDownView, cmpPoint);
        if touchDownView.resizePoint <> -1 then
        begin
          touchDownView.startRect := FCRect.Create(touchDownView.location.x, touchDownView.location.y, touchDownView.location.x + touchDownView.size.cx, touchDownView.location.y + touchDownView.size.cy);
        end;
			end;
    end;
end;

procedure HandleMouseUp(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);
var
  cmpPoint:FCPoint;
  inView:FCView;
  pName:PChar;
  tView:FCView;
begin
  paint.isDoubleClick := false;
  if touchDownView.isNotEmpty then
    begin
		cmpPoint := FCPoint.Create(mp.x - ClientX(touchDownView), mp.y - ClientY(touchDownView));
    inView := FindView(mp, gViews);
		if inView.isNotEmpty and (inView.uid = touchDownView.uid) then
      begin
			if paint.cancelClick = false then
        if OnClickEvent <> nil then
				  OnClickEvent(touchDownView, true, cmpPoint, false, cmpPoint, clicks)
        else
          OnClickDefault(touchDownView, true, cmpPoint, false, cmpPoint, clicks)
      end;
    if touchDownView.isNotEmpty then
      begin
      tView := touchDownView;
      touchDownView.resizePoint := -1;
      touchDownView := FCView.Create();
      touchDownView.isNotEmpty := false;
      touchDownView.uid := -1;
			touchMoveView := FCView.Create();
      touchMoveView.isNotEmpty := false;
      touchMoveView.uid := -1;
      if OnMouseUpEvent <> nil then
			  OnMouseUpEvent(tView, cmpPoint, buttons, clicks, 0)
      else
        OnMouseUpDefault(tView, cmpPoint, buttons, clicks, 0);
			if focusedView.isNotEmpty and focusedView.exView then
        begin
				pName := PChar(focusedView.viewName);
				FocusView(paint.gID, pName);
				MouseUpView(paint.gID, pName, trunc(cmpPoint.x), trunc(cmpPoint.y), buttons, clicks);
				InvalidateView(focusedView);
			  end;
      end;
    end;
  draggingView := FCView.Create();
  draggingView.isNotEmpty := false;
  draggingView.uid := -1;
end;

procedure HandleMouseMove(mp:FCPoint; buttons:integer; clicks:integer; delta:integer; var paint:FCPaint);
var
  cmpPoint:FCPoint;
  pName:PChar;
  offsetX:double;
  offsetY:double;
  newBounds:FCRect;
  pView:FCView;
  fView:FCView;
  oldMouseMoveView:FCView;
  pCursor:PChar;
begin
  if touchDownView.isNotEmpty then
    begin
		touchMoveView := touchDownView;
		cmpPoint := FCPoint.Create(mp.x - ClientX(touchDownView), mp.y - ClientY(touchDownView));
    if OnMouseMoveEvent <> nil then
		  OnMouseMoveEvent(touchDownView, cmpPoint, buttons, clicks, 0)
    else
      OnMouseMoveDefault(touchDownView, cmpPoint, buttons, clicks, 0);
    if paint.isDoubleClick = false then
      begin
			if focusedView.isNotEmpty and focusedView.exView then
        begin
				pName := PChar(focusedView.viewName);
				MouseMoveView(paint.gID, pName, trunc(cmpPoint.x), trunc(cmpPoint.y), 1, 1);
				InvalidateView(focusedView);
        end;
      if touchDownView.resizePoint <> -1 then
        begin
        newBounds := FCRect.Create(touchDownView.startRect.left, touchDownView.startRect.top, touchDownView.startRect.right, touchDownView.startRect.bottom);
        WindowResize(newBounds, touchDownView.resizePoint, mp, paint.touchDownPoint);
        touchDownView.location := FCPoint.Create(newBounds.left, newBounds.top);
        touchDownView.size := FCSize.Create(newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
        pView := touchDownView.GetParent();
        if pView.isNotEmpty then
          InvalidateView(pView)
        else
          Invalidate(paint);
        end
      else if touchDownView.allowDrag then
        begin
        if (Abs(mp.x - paint.touchDownPoint.x) > 5) or (Abs(mp.y - paint.touchDownPoint.y) > 5) then
          begin
          paint.dragBeginRect := FCRect.Create(touchDownView.location.x, touchDownView.location.y, touchDownView.location.x + touchDownView.size.cx, touchDownView.location.y + touchDownView.size.cy);
          paint.dragBeginPoint := FCPoint.Create(paint.touchDownPoint.x, paint.touchDownPoint.y);
          draggingView := touchDownView;
          touchDownView := FCView.Create();
          touchDownView.isNotEmpty := false;
          touchDownView.uid := -1;
          end;
        end;
      end;
    end
  else if draggingView.isNotEmpty and (buttons = 1) then
    begin
		offsetX := mp.x - paint.dragBeginPoint.x;
		offsetY := mp.y - paint.dragBeginPoint.y;
		newBounds := FCRect.Create(paint.dragBeginRect.left + offsetX, paint.dragBeginRect.top + offsetY, paint.dragBeginRect.right + offsetX, paint.dragBeginRect.bottom + offsetY);
		draggingView.location := FCPoint.Create(newBounds.left, newBounds.top);
    pView := draggingView.GetParent();
		if pView.isNotEmpty and (pView.viewType = 'split') then
      begin
      FCSplitLayoutDiv(pView).splitPercent := -1;
			ResetSplitLayoutDiv(FCSplitLayoutDiv(pView));
      if UpdateViewEvent <> nil then
        UpdateViewEvent(pView.views)
      else
        UpdateViewDefault(pView.views);
		  end;
		if pView.isNotEmpty then
			InvalidateView(pView)
		else
			Invalidate(paint);
    end
  else
    begin
      fView := FindView(mp, gViews);
      cmpPoint := FCPoint.Create(mp.x - ClientX(fView), mp.y - ClientY(fView));
      if fView.isNotEmpty then
        begin
        oldMouseMoveView := touchMoveView;
        touchMoveView := fView;
        if OnMouseMoveEvent <> nil then
          OnMouseMoveEvent(fView, cmpPoint, buttons, clicks, 0)
        else
          begin
          OnMouseMoveDefault(fView, cmpPoint, buttons, clicks, 0);
          end;
        end;
      pCursor := PChar(fView.cursor);
			SetCursor(paint.gID, pCursor);
    end;
end;

procedure SetAttributeDefault(var inView:FCView; node:integer);
var
  pName:PChar;
  pValue:PChar;
  attributesSize:integer;
  i:integer;
  sName:string;
  sValue:string;
  paint:FCPaint;
  lowerValue:string;
begin
  paint := inView.GetPaint();
  if paint.defaultUIStyle = 'dark' then
    begin
    inView.backColor := 'rgb(0,0,0)';
    inView.borderColor := 'rgb(100,100,100)';
    inView.textColor := 'rgb(255,255,255)';
    inView.scrollBarColor := 'rgb(100,100,100)';
    end
   else if paint.defaultUIStyle = 'light' then
    begin
    inView.backColor := 'rgb(255,255,255)';
    inView.borderColor := 'rgb(150,150,150)';
    inView.textColor := 'rgb(0,0,0)';
    inView.scrollBarColor := 'rgb(200,200,200)';
    end;
  attributesSize := GetXmlAttributesCount(node);
  for i := 0 to attributesSize - 1 do
  begin
    pName := GetXmlAttrName(node, i);
    sName := lowercase(StrPas(pName));
    pValue := GetXmlAttrValue(node, i);
    sValue := StrPas(pValue);
    if sName = 'location' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.location := FCPoint.Create(getSplitStrToInt(0), getSplitStrToInt(1));
      end
    else if sName = 'size' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.size := FCSize.Create(getSplitStrToInt(0), getSplitStrToInt(1));
      end
    else if sName = 'text' then
      begin
      inView.text := sValue;
      end
    else if sName = 'backcolor' then
      begin
      lowerValue := lowercase(sValue);
      if indexOfStr(PChar(lowerValue), PChar('rgb')) <> -1 then
        inView.backColor := lowerValue
      else
        inView.backColor := 'none';
      end
    else if sName = 'bordercolor' then
      begin
      lowerValue := lowercase(sValue);
      if indexOfStr(PChar(lowerValue), PChar('rgb')) <> -1 then
        inView.borderColor := lowerValue
      else
        inView.borderColor := 'none';
      end
    else if sName = 'textcolor' then
      begin
      lowerValue := lowercase(sValue);
      if indexOfStr(PChar(lowerValue), PChar('rgb')) <> -1 then
        inView.textColor := lowerValue
      else
        inView.textColor := 'none';
      end
    else if sName = 'layoutstyle' then
      begin
      lowerValue := lowercase(sValue);
      if inView.viewType = 'layout' then
        (FCLayoutDiv(inView)).layoutStyle := lowerValue
      else if inView.viewType = 'split' then
        (FCSplitLayoutDiv(inView)).layoutStyle := lowerValue;
      end
    else if sName = 'align' then
      begin
      lowerValue := lowercase(sValue);
      inView.align := lowerValue;
      end
    else if sName = 'cursor' then
      begin
      lowerValue := lowercase(sValue);
      inView.cursor := lowerValue;
      end
    else if sName = 'vertical-align' then
      begin
      lowerValue := lowercase(sValue);
      inView.verticalAlign := lowerValue;
      end
    else if sName = 'dock' then
      begin
      lowerValue := lowercase(sValue);
      inView.dock := lowerValue;
      end
    else if sName = 'font' then
      begin
      inView.font := sValue;
      end
    else if sName = 'headerheight' then
      begin
      splitStr(PChar(sValue), PChar(','));
      if inView.viewType = 'tree' then
        (FCTree(inView)).headerHeight := getSplitStrToInt(0)
      else if inView.viewType = 'grid' then
        (FCGrid(inView)).headerHeight := getSplitStrToInt(0);
      end
    else if sName = 'cornerradius' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.cornerRadius := getSplitStrToInt(0);
      end
    else if sName = 'tabindex' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.tabIndex := getSplitStrToInt(0);
      end
    else if sName = 'tabstop' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.tabStop := true
        else
          inView.tabStop := false;
      end
    else if sName = 'borderwidth' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.borderWidth := getSplitStrToInt(0);
      end
    else if sName = 'splitmode' then
      begin
      lowerValue := lowercase(sValue);
      if inView.viewType = 'split' then
        (FCSplitLayoutDiv(inView)).splitMode := lowerValue;
      end
    else if sName = 'autowrap' then
      begin
      lowerValue := lowercase(sValue);
      if inView.viewType = 'layout' then
      begin
        if lowerValue = 'true' then
          (FCLayoutDiv(inView)).autoWrap := true
        else
          (FCLayoutDiv(inView)).autoWrap := false;
      end;
      end
    else if sName = 'name' then
      begin
      inView.viewName := sValue;
      end
    else if sName = 'enabled' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.enabled := true
        else
          inView.enabled := false;
      end
    else if sName = 'showvscrollbar' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.showVScrollBar := true
        else
          inView.showVScrollBar := false;
      end
    else if sName = 'showhscrollbar' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.showHScrollBar := true
        else
          inView.showHScrollBar := false;
      end
    else if sName = 'visible' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.visible := true
        else
          inView.visible := false;
      end
    else if sName = 'displayoffset' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.displayoffset := true
        else
          inView.displayoffset := false;
      end
    else if sName = 'checked' then
      begin
      lowerValue := lowercase(sValue);
      if inView.viewType = 'radiobutton' then
      begin
        if lowerValue = 'true' then
          (FCRadioButton(inView)).checked := true
        else
          (FCRadioButton(inView)).checked := false;
      end
      else if inView.viewType = 'checkbox' then
        if lowerValue = 'true' then
          (FCCheckBox(inView)).checked := true
        else
          (FCCheckBox(inView)).checked := false;
      begin
      end;
      end
    else if sName = 'buttonsize' then
      begin
      splitStr(PChar(sValue), PChar(','));
      if inView.viewType = 'radiobutton' then
      begin
        (FCRadioButton(inView)).buttonSize := FCSize.Create(getSplitStrToInt(0), getSplitStrToInt(1));
      end
      else if inView.viewType = 'checkbox' then
        (FCCheckBox(inView)).buttonSize := FCSize.Create(getSplitStrToInt(0), getSplitStrToInt(1));
      begin
      end;
      end
    else if sName = 'topmost' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.topMost := true
        else
          inView.topMost := false;
      end
    else if sName = 'groupname' then
      begin
      if inView.viewType = 'layout' then
        (FCRadioButton(inView)).groupName := sValue;
      end
    else if sName = 'allowdragscroll' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.allowDragScroll := true
        else
          inView.allowDragScroll := false;
      end
    else if sName = 'allowpreviewsevent' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.allowPreviewsEvent := true
        else
          inView.allowPreviewsEvent := false;
      end
    else if sName = 'allowdrag' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.allowDrag := true
        else
          inView.allowDrag := false;
      end
    else if sName = 'allowresize' then
      begin
      lowerValue := lowercase(sValue);
      if lowerValue = 'true' then
          inView.allowResize := true
        else
          inView.allowResize := false;
      end
    else if sName = 'indent' then
      begin
      splitStr(PChar(sValue), PChar(','));
      if inView.viewType = 'tree' then
      begin
        if lowerValue = 'true' then
          (FCTree(inView)).indent := getSplitStrToInt(0)
        else
          (FCTree(inView)).indent := getSplitStrToInt(0);
      end;
      end
    else if sName = 'showcheckbox' then
      begin
      lowerValue := lowercase(sValue);
      if inView.viewType = 'tree' then
      begin
        if lowerValue = 'true' then
          (FCTree(inView)).showCheckBox := true
        else
          (FCTree(inView)).showCheckBox := false;
      end;
      end
    else if sName = 'padding' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.padding := FCPadding.Create(getSplitStrToInt(0), getSplitStrToInt(1), getSplitStrToInt(2), getSplitStrToInt(3));
      end
    else if sName = 'margin' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.margin := FCPadding.Create(getSplitStrToInt(0), getSplitStrToInt(1), getSplitStrToInt(2), getSplitStrToInt(3));
      end
    else if sName = 'hoveredcolor' then
      begin
      lowerValue := lowercase(sValue);
      if indexOfStr(PChar(lowerValue), PChar('rgb')) <> -1 then
        inView.hoveredColor := lowerValue
      else
        inView.hoveredColor := 'none';
      end
    else if sName = 'pushedcolor' then
      begin
      lowerValue := lowercase(sValue);
      if indexOfStr(PChar(lowerValue), PChar('rgb')) <> -1 then
        inView.pushedColor := lowerValue
      else
        inView.pushedColor := 'none';
      end
    else if sName = 'layout' then
      begin
      lowerValue := lowercase(sValue);
      if inView.viewType = 'tabview' then
      begin
        if lowerValue = 'true' then
          (FCTabView(inView)).layout := lowerValue
        else
          (FCTabView(inView)).layout := lowerValue;
      end;
      end
    else if sName = 'width' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.size.cx := getSplitStrToInt(0);
      end
    else if sName = 'height' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.size.cy := getSplitStrToInt(0);
      end
    else if sName = 'top' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.location.y := getSplitStrToInt(0);
      end
    else if sName = 'left' then
      begin
      splitStr(PChar(sValue), PChar(','));
      inView.location.x := getSplitStrToInt(0);
      end
  end;
end;

procedure ReadXmlNodeDefault(var paint:FCPaint; node:integer; var parent:FCView);
var
  pName:PChar;
  pValue:PChar;
  nodeName:string;
  childNodesSize:integer;
  i:integer;
  child:integer;
  inView:FCView;
  typeStr:string;
  aName:string;
  aValue:string;
  j:integer;
  attributesSize:integer;
  cid:string;
  tButton:FCView;
  pLength:integer;
  tabPages:array of FCTabPage;
  tabPagesLength:integer;
  selectedIndex:integer;
  splitter:FCView;
  splitlayoutDiv:FCSplitLayoutDiv;
  splitSize:integer;
  splitRect:FCRect;
  sSize:integer;
  sPosition:integer;
  tChildSize:integer;
  t:integer;
  subNodeName:string;
  childNodeID:integer;
  m:integer;
  sunNodeName:string;
  sunNodeID:integer;
  sunChildSize:integer;
  gridColumn:FCGridColumn;
  grid:FCGrid;
  columnsSize:integer;
begin
  childNodesSize := GetXmlChildNodesCount(node);
  for i := 0 to childNodesSize - 1 do
  begin
    child := GetXmlChildNodeID(node, i);
    pName := GetXmlNodeName(child);
    nodeName := StrPas(pName);
    inView := FCView.Create();
    inView.isNotEmpty := false;
    typeStr := '';
    if (nodeName = 'div') or (nodeName = 'view') then
    begin
      attributesSize := GetXmlAttributesCount(child);
      for j := 0 to attributesSize - 1 do
      begin
        pName := GetXmlAttrName(child, j);
        aName := lowercase(StrPas(pName));
        if aName = 'type' then
          begin
          pValue := GetXmlAttrValue(child, j);
          aValue := StrPas(pValue);
          typeStr := aValue;
          break;
          end;
      end;
      if typeStr = 'splitlayout' then
        begin
        inView := FCSplitLayoutDiv.Create();
        end
      else if typeStr = 'layout' then
        inView := FCLayoutDiv.Create()
      else if typeStr = 'tab' then
        inView := FCTabView.Create()
      else if typeStr = 'tabpage' then
        inView := FCTabPage.Create()
      else if typeStr = 'radio' then
        inView := FCRadioButton.Create()
      else if typeStr = 'checkbox' then
        inView := FCCheckBox.Create()
      else if (typeStr = 'text') or (typeStr = 'range') or (typeStr = 'datetime') then
        inView := FCTextBox.Create()
      else if typeStr = 'custom' then
        begin
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          if aName = 'cid' then
            begin
            pValue := GetXmlAttrValue(child, j);
            aValue := StrPas(pValue);
            cid := aValue;
            break;
            end;
        end;
        inView := FCDiv.Create();
        inView.viewType := cid;
        end
      else
        begin
        inView := FCDiv.Create();
        end;
    end
    else if nodeName = 'input' then
      begin
      attributesSize := GetXmlAttributesCount(child);
      for j := 0 to attributesSize - 1 do
      begin
        pName := GetXmlAttrName(child, j);
        aName := lowercase(StrPas(pName));
        if aName = 'type' then
          begin
          pValue := GetXmlAttrValue(child, j);
          aValue := StrPas(pValue);
          typeStr := aValue;
          break;
          end;
      end;
      if typeStr = 'radio' then
        inView := FCRadioButton.Create()
      else if typeStr = 'checkbox' then
        inView := FCCheckBox.Create()
      else if (typeStr = 'text') or (typeStr = 'range') or (typeStr = 'datetime') then
        inView := FCTextBox.Create()
      else if typeStr = 'custom' then
        begin
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          if aName = 'cid' then
            begin
            pValue := GetXmlAttrValue(child, j);
            aValue := StrPas(pValue);
            cid := aValue;
            break;
            end;
        end;
        inView := FCDiv.Create();
        inView.viewType := cid;
        end 
      else
        begin
        inView := FCButton.Create();
        end;
      end
    else if nodeName = 'chart' then
      inView := FCChart.Create()
    else if nodeName = 'calendar' then
      inView := FCCalendar.Create()
    else if nodeName = 'table' then
      inView := FCGrid.Create()
    else if nodeName = 'tree' then
      inView := FCTree.Create()
    else if nodeName = 'label' then
      inView := FCLabel.Create()
    else
      begin
      inView := FCView.Create();
      end;
    inView.setPaint(paint);
    if parent.isNotEmpty then
      begin
      inView.setParent(parent);
      end;
    setAttributeDefault(inView, child);
    if inView.isNotEmpty then
    begin
      if typeStr = 'tabpage' then
        begin
        tButton := FCButton.Create();
        tButton.viewType := 'tabbutton';
        attributesSize := GetXmlAttributesCount(child);
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          if aName = 'headersize' then
            begin
            pValue := GetXmlAttrValue(child, j);
            aValue := StrPas(pValue);
            splitStr(PChar(aValue), PChar(','));
            tButton.size := FCSize.Create(getSplitStrToInt(0), getSplitStrToInt(1));
            break;
            end;
        end;
        if paint.defaultUIStyle = 'dark' then
          begin
          tButton.backColor := 'rgb(0,0,0)';
          tButton.borderColor := 'rgb(100,100,100)';
          tButton.textColor := 'rgb(255,255,255)';
          end
        else if paint.defaultUIStyle = 'light' then
          begin
          tButton.backColor := 'rgb(255,255,255)';
          tButton.borderColor := 'rgb(150,150,150)';
          tButton.textColor := 'rgb(0,0,0)';
          end;
        tButton.text := inView.text;
        tButton.SetPaint(paint);
        AddTabPage(FCTabView(parent), FCTabPage(inView), tButton);
        end
      else
        begin
          if parent.isNotEmpty then
          begin
            pLength := High(parent.views) - Low(parent.views) + 1;
            SetLength(parent.views, pLength + 1);
            parent.views[pLength] := inView;
          end
          else
          begin
            pLength := High(gViews) - Low(gViews) + 1;
            SetLength(gViews, pLength + 1);
            gViews[pLength] := inView;
          end;
        end;
      if typeStr = 'splitlayout' then
      begin
        attributesSize := GetXmlAttributesCount(child);
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          if aName = 'datumsize' then
          begin
            pValue := GetXmlAttrValue(child, j);
            aValue := StrPas(pValue);
            splitStr(PChar(aValue), PChar(','));
            inView.size := FCSize.Create(getSplitStrToInt(0), getSplitStrToInt(1));
            break;
          end;
        end;
        splitter := FCView.Create();
				splitter.SetPaint(paint);
				splitter.SetParent(inView);
				if paint.defaultUIStyle = 'dark' then
					splitter.backColor := 'rgb(75,75,75)'
				else if paint.defaultUIStyle = 'light' then
        begin
					splitter.backColor := 'rgb(150,150,150)';
        end;
        splitter.borderColor := 'none';
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          if aName = 'candragsplitter' then
          begin
            pValue := GetXmlAttrValue(child, j);
            aValue := StrPas(pValue);
            if aValue = 'true' then
              begin
              splitter.allowDrag := true;
              break;
              end;
          end;
        end;
        splitlayoutDiv := FCSplitLayoutDiv(inView);
        splitlayoutDiv.splitter := splitter;
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          if aName = 'splitterposition' then
          begin
            pValue := GetXmlAttrValue(child, j);
            aValue := StrPas(pValue);
            splitSize := splitStr(PChar(aValue), PChar(','));
            if splitSize >= 4 then
            begin
              splitRect := FCRect.Create(getSplitStrToInt(0), getSplitStrToInt(1), getSplitStrToInt(2), getSplitStrToInt(3));
              splitter.location := FCPoint.Create(splitRect.left, splitRect.top);
					    splitter.size := FCSize.Create(splitRect.right - splitRect.left, splitRect.bottom - splitRect.top);
            end
            else
            begin
              aValue := StrPas(pValue);
              sSize := getSplitStrToInt(1);
              sPosition := getSplitStrToInt(0);
              if (splitlayoutDiv.layoutStyle = 'lefttoright') or (splitlayoutDiv.layoutStyle = 'righttoleft') then
                begin
                splitter.location := FCPoint.Create(sPosition, 0);
                splitter.size := FCSize.Create(sSize, inView.size.cy);
                end
              else
                begin
                splitter.location := FCPoint.Create(0, sPosition);
                splitter.size := FCSize.Create(inView.size.cx, sSize);
                end;
            end;
            break;
          end;
        end;
        ReadXmlNodeDefault(paint, child, inView);
        splitlayoutDiv.firstView := inView.views[0];
				splitlayoutDiv.secondView := inView.views[1];
        pLength := High(inView.views) - Low(inView.views) + 1;
        SetLength(inView.views, pLength + 1);
        inView.views[pLength] := splitter;
				splitlayoutDiv.oldSize := FCSize.Create(inView.size.cx, inView.size.cy);
				resetSplitLayoutDiv(splitlayoutDiv);
      end
      else if typeStr = 'tab' then
      begin
        ReadXmlNodeDefault(paint, child, inView);
				tabPages := FCTabView(inView).tabPages;
        tabPagesLength := High(tabPages) - Low(tabPages)  + 1;
        selectedIndex := -1;
				if tabPagesLength > 0 then
        begin
          attributesSize := GetXmlAttributesCount(child);
          for j := 0 to attributesSize - 1 do
          begin
            pName := GetXmlAttrName(child, j);
            aName := lowercase(StrPas(pName));
            if aName = 'selectedindex' then
            begin
              pValue := GetXmlAttrValue(child, j);
              aValue := StrPas(pValue);
              splitStr(PChar(aValue), PChar(','));
              selectedIndex := getSplitStrToInt(0);
              if (selectedIndex >= 0) and (selectedIndex < tabPagesLength) then
							  tabPages[selectedIndex].visible := true
						  else
							  tabPages[tabPagesLength - 1].visible := true;
              break;
            end;
          end;
          if selectedIndex = -1 then
            tabPages[tabPagesLength - 1].visible := true;
        end;
      end
      else if nodeName = 'table' then
      begin
        tChildSize := getXmlChildNodesCount(child);
        grid := FCGrid(inView);
        for t := 0 to tChildSize - 1 do
        begin
          childNodeID := getXmlChildNodeID(child, t);
          pName := GetXmlNodeName(childNodeID);
          subNodeName := StrPas(pName);
          if subNodeName = 'tr' then
          begin
            sunChildSize := getXmlChildNodesCount(childNodeID);
            for m := 0 to sunChildSize - 1 do
            begin
              sunNodeID := getXmlChildNodeID(childNodeID, m);
              pName := GetXmlNodeName(sunNodeID);
              sunNodeName := StrPas(pName);
              if sunNodeName = 'th' then
              begin
                gridColumn := FCGridColumn.Create();
								if paint.defaultUIStyle = 'light' then
                  begin
									gridColumn.backColor := 'rgb(230,230,230)';
									gridColumn.borderColor := 'rgb(150,150,150)';
									gridColumn.textColor := 'rgb(0,0,0)';
                  end
								else if paint.defaultUIStyle = 'dark' then
                  begin
									gridColumn.backColor := 'rgb(50,50,50)';
									gridColumn.borderColor := 'rgb(100,100,100)';
									gridColumn.textColor := 'rgb(255,255,255)';
                  end;
                attributesSize := GetXmlAttributesCount(sunNodeID);
                for j := 0 to attributesSize - 1 do
                begin
                  pName := GetXmlAttrName(sunNodeID, j);
                  aName := lowercase(StrPas(pName));
                  pValue := GetXmlAttrValue(sunNodeID, j);
                  aValue := StrPas(pValue);
                  if aName = 'text' then
                    gridColumn.text := aValue
                  else if aName = 'width' then
                  begin
                    splitStr(PChar(aValue), PChar(','));
                    gridColumn.width := getSplitStrToInt(0);
                  end
                  else if aName = 'backcolor' then
                    gridColumn.backColor := aValue
                  else if aName = 'textcolor' then
                    gridColumn.textcolor := aValue
                  else if aName = 'bordercolor' then
                    gridColumn.borderColor := aValue
                  else if aName = 'font' then
                    gridColumn.font := aValue;
                end;
                columnsSize := High(grid.columns) - Low(grid.columns) + 1;
                SetLength(grid.columns, columnsSize + 1);
                grid.columns[columnsSize] := gridColumn;
              end;
            end;
          end;
        end;
      end
      else if inView.viewType = 'textbox' then
      begin
        inView.exView := true;
        CreateView(paint.gID, PChar(inView.viewType), PChar(inView.viewName));
        if paint.defaultUIStyle = 'dark' then
          begin
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar('backcolor'), PChar('rgb(0,0,0)'));
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar('bordercolor'), PChar('rgb(100,100,100)'));
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar('textcolor'), PChar('rgb(255,255,255)'));
          end
        else if paint.defaultUIStyle = 'light' then
          begin
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar('backcolor'), PChar('rgb(255,255,255)'));
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar('bordercolor'), PChar('rgb(150,150,150)'));
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar('textcolor'), PChar('rgb(0,0,0)'));
          end;
        attributesSize := GetXmlAttributesCount(child);
        for j := 0 to attributesSize - 1 do
        begin
          pName := GetXmlAttrName(child, j);
          aName := lowercase(StrPas(pName));
          pValue := GetXmlAttrValue(child, j);
          aValue := StrPas(pValue);
          SetAttribute2(paint.gID, PChar(inView.viewName), PChar(aName), PChar(aValue));
        end;
      end
      else if nodeName = 'calendar' then
      begin
        InitCalendar(FCCalendar(inView));
        FCCalendar(inView).selectedDay := GetYear(FCCalendar(inView), 2023).months[10].days[1];
      end
      else
      begin
        if inView.viewType <> 'chart' then
          ReadXmlNodeDefault(paint, child, inView);
      end;
    end;
  end;
end;

procedure RenderFaceCat(var paint:FCPaint; xmlPath:string);
var
  pName:PChar;
  rootNode:integer;
  childNodesSize:integer;
  i:integer;
  childNodeID:integer;
  pSubNodeName:PChar;
  noneView:FCView;
begin
  touchDownView := FCView.Create();
  touchDownView.isNotEmpty := false;
  touchDownView.uid := -1;
  focusedView := FCView.Create();
  focusedView.isNotEmpty := false;
  focusedView.uid := -1;
  draggingView := FCView.Create();
  draggingView.isNotEmpty := false;
  draggingView.uid := -1;
  touchMoveView := FCView.Create();
  touchMoveView.isNotEmpty := false;
  touchMoveView.uid := -1;
  pName := PChar(xmlPath);
  ReadXmlDoc(pName);
  rootNode := GetXmlRootNode();
  childNodesSize := GetXmlChildNodesCount(rootNode);
  noneView := FCView.Create();
  noneView.isNotEmpty := false;
  for i := 0 to childNodesSize - 1 do
  begin
    childNodeID := GetXmlChildNodeID(rootNode, i);
    pSubNodeName := GetXmlNodeName(childNodeID);
    if pSubNodeName = 'body' then
      ReadXmlNodeDefault(paint, childNodeID, noneView);
  end;
  DeleteXmlDoc();
  if UpdateViewEvent <> nil then
    UpdateViewEvent(gViews)
  else
    UpdateViewDefault(gViews);
	Invalidate(paint);
end;

procedure WndProcDefault(var paint:FCPaint; hWnd:integer; message:integer; wParam:integer; lParam:integer); 
var
  ccx:integer;
  ccy:integer;
  mp:FCPoint;
  allRect:FCRect;
  drawRect:FCRect;
  clipRect:FCRect;
begin
  if message = WM_LBUTTONDOWN then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		HandleMouseDown(mp, 1, 1, 0, paint);
    end
	else if message = WM_RBUTTONDOWN then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		HandleMouseDown(mp, 2, 1, 0, paint);
    end
	else if message = WM_LBUTTONDBLCLK then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		HandleMouseDown(mp, 1, 2, 0, paint);
    end
	else if message = WM_RBUTTONDBLCLK then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		HandleMouseDown(mp, 2, 2, 0, paint);
    end
	else if message = WM_LBUTTONUP then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		if paint.isDoubleClick then
			HandleMouseUp(mp, 1, 2, 0, paint)
		else
			HandleMouseUp(mp, 1, 1, 0, paint);
		end
	else if message = WM_RBUTTONUP then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		if paint.isDoubleClick then
			HandleMouseUp(mp, 2, 2, 0, paint)
		else
			HandleMouseUp(mp, 2, 1, 0, paint);
		end
	else if message = WM_MOUSEMOVE then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		if wParam = 1  then
			HandleMouseMove(mp, 1, 1, 0, paint)
		else if wParam = 2 then
			HandleMouseMove(mp, 2, 1, 0, paint)
		else
			HandleMouseMove(mp, 0, 0, 0, paint);
		end
	else if message = WM_MOUSEWHEEL then
    begin
		ccx := GetMouseX(paint.hWnd);
		ccy := GetMouseY(paint.hWnd);
		mp := FCPoint.Create(ccx, ccy);
		mp.x := mp.x / paint.scaleFactorX;
		mp.y := mp.y / paint.scaleFactorY;
		if wParam < 0 then
			HandleMouseWheel(mp, 0, 0, -1, paint)
		else
			HandleMouseWheel(mp, 0, 0, 1, paint);
		end
  else if (message = WM_IME_COMPOSITION) or (message = WM_IME_CHAR) or (message = WM_IME_SETCONTEXT) then
    begin
		SetMessageState(paint.gID, 1);
    end
  else if (message = WM_CHAR) or (message = WM_KEYDOWN) or (message = WM_SYSKEYDOWN) or (message = WM_KEYUP) or (message = WM_SYSKEYUP) then
    begin
		if focusedView.isNotEmpty then
      begin
			if focusedView.exView then
        begin
				SetMessageState(paint.gID, 1);
				InvalidateView(focusedView);
        end;
			if (message = WM_KEYDOWN) or (message = WM_SYSKEYDOWN) then
        begin
        if OnKeyDownEvent <> nil then
          OnKeyDownEvent(focusedView, wParam)
        else
          OnKeyDownDefault(focusedView, wParam);
        end
      else if (message = WM_KEYUP) or (message = WM_SYSKEYUP) then
        begin
        if OnKeyUpEvent <> nil then
          OnKeyUpEvent(focusedView, wParam)
        else
          OnKeyUpDefault(focusedView, wParam);
        end
      else if message = WM_CHAR then
        begin
        if OnCharEvent <> nil then
          OnCharEvent(focusedView, wParam)
        else
          OnCharDefault(focusedView, wParam);
        end;
      end;
		end
  else if (message = WM_PAINT) or (message = WM_SIZE) then
    begin
    ccx := getWindowWidth(paint.hWnd);
    ccy := getWindowHeight(paint.hWnd);
    if (ccx > 0) and (ccy > 0) then
    begin
      paint.size := FCSize.Create(ccx, ccy);
      if UpdateViewEvent <> nil then
        UpdateViewEvent(gViews)
      else
        UpdateViewDefault(gViews);
      BeginWmPaint(paint.hWnd);
      clipRect := FCRect.Create(0, 0, 0, 0);
      clipRect.isNotEmpty := false;
      paint.clipRect := clipRect;
      allRect := FCRect.Create(0, 0, paint.size.cx / paint.scaleFactorX, paint.size.cy / paint.scaleFactorY);
      drawRect := allRect;
      paint.BeginPaint(allRect, drawRect);
      RenderViews(gViews, paint, drawRect);
      paint.EndPaint();
      EndWmPaint(paint.hWnd);
      end;
    end;
end;
end.
